EasyWidgets 0.4__tar.gz → 0.4.2__tar.gz
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.
- {EasyWidgets-0.4 → easywidgets-0.4.2}/EasyWidgets.egg-info/PKG-INFO +16 -6
- easywidgets-0.4.2/EasyWidgets.egg-info/entry_points.txt +7 -0
- {EasyWidgets-0.4 → easywidgets-0.4.2}/PKG-INFO +16 -6
- {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/fields.py +2 -2
- {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/middleware.py +4 -3
- {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/resource.py +3 -1
- easywidgets-0.4.2/ew/tests/helpers.py +15 -0
- {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/tests/test_fields.py +142 -112
- {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/tests/test_resource.py +18 -13
- {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/tests/test_utils.py +17 -11
- {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/tests/test_widget.py +3 -3
- {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/validators.py +5 -5
- {EasyWidgets-0.4 → easywidgets-0.4.2}/setup.py +9 -4
- EasyWidgets-0.4/EasyWidgets.egg-info/entry_points.txt +0 -11
- EasyWidgets-0.4/ew/tests/helpers.py +0 -18
- {EasyWidgets-0.4 → easywidgets-0.4.2}/EasyWidgets.egg-info/SOURCES.txt +0 -0
- {EasyWidgets-0.4 → easywidgets-0.4.2}/EasyWidgets.egg-info/dependency_links.txt +0 -0
- {EasyWidgets-0.4 → easywidgets-0.4.2}/EasyWidgets.egg-info/not-zip-safe +0 -0
- {EasyWidgets-0.4 → easywidgets-0.4.2}/EasyWidgets.egg-info/requires.txt +0 -0
- {EasyWidgets-0.4 → easywidgets-0.4.2}/EasyWidgets.egg-info/top_level.txt +0 -0
- {EasyWidgets-0.4 → easywidgets-0.4.2}/MANIFEST.in +0 -0
- {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/__init__.py +0 -0
- {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/core.py +0 -0
- {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/errors.py +0 -0
- {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/forms.py +0 -0
- {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/jinja2_ew.py +0 -0
- {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/render.py +0 -0
- {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/select.py +0 -0
- {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/templates/__init__.py +0 -0
- {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/templates/jinja2/__init__.py +0 -0
- {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/templates/jinja2/_ew_lib.html +0 -0
- {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/templates/jinja2/checkbox.html +0 -0
- {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/templates/jinja2/checkbox_set.html +0 -0
- {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/templates/jinja2/field_set.html +0 -0
- {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/templates/jinja2/google_analytics.html +0 -0
- {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/templates/jinja2/repeated_field.html +0 -0
- {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/templates/jinja2/row_field.html +0 -0
- {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/templates/jinja2/select_field.html +0 -0
- {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/templates/jinja2/simple_form.html +0 -0
- {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/templates/jinja2/table_field.html +0 -0
- {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/tests/__init__.py +0 -0
- {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/tests/templates/__init__.py +0 -0
- {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/tests/templates/simple.html +0 -0
- {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/utils.py +0 -0
- {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/widget.py +0 -0
- {EasyWidgets-0.4 → easywidgets-0.4.2}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 1
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
2
|
Name: EasyWidgets
|
|
3
|
-
Version: 0.4
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: A minimalistic approach to HTML generation and validation with TurboGears
|
|
5
5
|
Home-page: https://sourceforge.net/p/easywidgets/code/
|
|
6
6
|
Author: Rick Copeland
|
|
@@ -8,9 +8,7 @@ Author-email: rick446@usa.net
|
|
|
8
8
|
License: MIT
|
|
9
9
|
Project-URL: Documentation, http://easywidgets.pythonisito.com
|
|
10
10
|
Project-URL: Source Code, https://sourceforge.net/p/easywidgets/code/
|
|
11
|
-
Description: Not so easy.
|
|
12
11
|
Keywords: TurboGears FormEncode TurboGears2
|
|
13
|
-
Platform: UNKNOWN
|
|
14
12
|
Classifier: Development Status :: 3 - Alpha
|
|
15
13
|
Classifier: Environment :: Web Environment
|
|
16
14
|
Classifier: Framework :: TurboGears
|
|
@@ -20,5 +18,17 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
20
18
|
Classifier: Natural Language :: English
|
|
21
19
|
Classifier: Operating System :: OS Independent
|
|
22
20
|
Classifier: Programming Language :: Python
|
|
23
|
-
Classifier: Programming Language :: Python :: 3.
|
|
24
|
-
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
26
|
+
Requires-Python: >=3.8
|
|
27
|
+
Requires-Dist: python-dateutil
|
|
28
|
+
Requires-Dist: formencode
|
|
29
|
+
Requires-Dist: markupsafe
|
|
30
|
+
Requires-Dist: paste
|
|
31
|
+
Requires-Dist: webob
|
|
32
|
+
Requires-Dist: six>=1.13.0
|
|
33
|
+
|
|
34
|
+
Not so easy.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 1
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
2
|
Name: EasyWidgets
|
|
3
|
-
Version: 0.4
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: A minimalistic approach to HTML generation and validation with TurboGears
|
|
5
5
|
Home-page: https://sourceforge.net/p/easywidgets/code/
|
|
6
6
|
Author: Rick Copeland
|
|
@@ -8,9 +8,7 @@ Author-email: rick446@usa.net
|
|
|
8
8
|
License: MIT
|
|
9
9
|
Project-URL: Documentation, http://easywidgets.pythonisito.com
|
|
10
10
|
Project-URL: Source Code, https://sourceforge.net/p/easywidgets/code/
|
|
11
|
-
Description: Not so easy.
|
|
12
11
|
Keywords: TurboGears FormEncode TurboGears2
|
|
13
|
-
Platform: UNKNOWN
|
|
14
12
|
Classifier: Development Status :: 3 - Alpha
|
|
15
13
|
Classifier: Environment :: Web Environment
|
|
16
14
|
Classifier: Framework :: TurboGears
|
|
@@ -20,5 +18,17 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
20
18
|
Classifier: Natural Language :: English
|
|
21
19
|
Classifier: Operating System :: OS Independent
|
|
22
20
|
Classifier: Programming Language :: Python
|
|
23
|
-
Classifier: Programming Language :: Python :: 3.
|
|
24
|
-
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
26
|
+
Requires-Python: >=3.8
|
|
27
|
+
Requires-Dist: python-dateutil
|
|
28
|
+
Requires-Dist: formencode
|
|
29
|
+
Requires-Dist: markupsafe
|
|
30
|
+
Requires-Dist: paste
|
|
31
|
+
Requires-Dist: webob
|
|
32
|
+
Requires-Dist: six>=1.13.0
|
|
33
|
+
|
|
34
|
+
Not so easy.
|
|
@@ -50,8 +50,8 @@ class FieldWidget(Widget, fev.Validator):
|
|
|
50
50
|
if 'value' in context:
|
|
51
51
|
try:
|
|
52
52
|
context['value'] = self.from_python(context['value'], None)
|
|
53
|
-
except Exception
|
|
54
|
-
warnings.warn('suppressed an error that you should probably fix. ' + traceback.format_exc(
|
|
53
|
+
except Exception:
|
|
54
|
+
warnings.warn('suppressed an error that you should probably fix. ' + traceback.format_exc(),
|
|
55
55
|
EasyWidgetsWarning,
|
|
56
56
|
stacklevel=4,
|
|
57
57
|
)
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import urllib
|
|
2
2
|
import logging
|
|
3
3
|
|
|
4
4
|
from webob import exc
|
|
5
5
|
from paste import fileapp
|
|
6
|
+
from urllib.parse import urlparse
|
|
6
7
|
|
|
7
8
|
from .core import widget_context, WidgetContext
|
|
8
9
|
from .resource import ResourceManager
|
|
@@ -68,11 +69,11 @@ class WidgetMiddleware:
|
|
|
68
69
|
result = self.app(environ, start_response)
|
|
69
70
|
elif environ['PATH_INFO'].startswith(self.script_name_slim_js):
|
|
70
71
|
result = self.serve_slim_js(
|
|
71
|
-
mgr,
|
|
72
|
+
mgr, urllib.parse.parse_qs(environ['QUERY_STRING']).get('href', [''])[0],
|
|
72
73
|
environ, start_response)
|
|
73
74
|
elif environ['PATH_INFO'].startswith(self.script_name_slim_css):
|
|
74
75
|
result = self.serve_slim_css(
|
|
75
|
-
mgr,
|
|
76
|
+
mgr, urllib.parse.parse_qs(environ['QUERY_STRING']).get('href', [''])[0],
|
|
76
77
|
environ, start_response)
|
|
77
78
|
else:
|
|
78
79
|
result = self.serve_resource(mgr, environ['PATH_INFO'][len(self.script_name):], environ, start_response)
|
|
@@ -140,6 +140,8 @@ class ResourceManager:
|
|
|
140
140
|
pass
|
|
141
141
|
def get_plain(h):
|
|
142
142
|
fn = self.get_filename(h)
|
|
143
|
+
if not fn:
|
|
144
|
+
return ''
|
|
143
145
|
return open(fn, encoding='utf-8').read()
|
|
144
146
|
def get_min_js(h):
|
|
145
147
|
if '.min.' in h:
|
|
@@ -179,7 +181,7 @@ class ResourceManager:
|
|
|
179
181
|
except ImportError: # pragma no cover
|
|
180
182
|
pass
|
|
181
183
|
joiner = ';\n' if file_type == 'js' else '\n'
|
|
182
|
-
content = joiner.join(getter(h) for h in href.split(';') )
|
|
184
|
+
content = joiner.join(getter(h) for h in href.split(';') if h)
|
|
183
185
|
if self.use_cache:
|
|
184
186
|
self.resource_cache[href] = content
|
|
185
187
|
return content
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from paste.registry import Registry
|
|
2
|
+
from ew import widget_context, TemplateEngine
|
|
3
|
+
from ew.core import WidgetContext
|
|
4
|
+
from ew.resource import ResourceManager
|
|
5
|
+
|
|
6
|
+
REGISTRY = Registry()
|
|
7
|
+
REGISTRY.prepare()
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def setup_method():
|
|
11
|
+
TemplateEngine.initialize({})
|
|
12
|
+
mgr = ResourceManager()
|
|
13
|
+
REGISTRY.register(
|
|
14
|
+
widget_context,
|
|
15
|
+
WidgetContext(scheme='http', resource_manager=mgr))
|
|
@@ -3,18 +3,24 @@ from datetime import date, time
|
|
|
3
3
|
import formencode as fe
|
|
4
4
|
from formencode import validators as fev
|
|
5
5
|
from bs4 import BeautifulSoup
|
|
6
|
+
from ew.tests.helpers import setup_method
|
|
6
7
|
|
|
7
8
|
import ew
|
|
8
9
|
import ew.jinja2_ew
|
|
9
|
-
|
|
10
|
+
import pytest
|
|
11
|
+
|
|
10
12
|
|
|
11
13
|
def soup(text):
|
|
12
|
-
soup = BeautifulSoup(text)
|
|
14
|
+
soup = BeautifulSoup(text, "html.parser")
|
|
13
15
|
for n in soup.findAll():
|
|
14
16
|
n.attrs = sorted(n.attrs)
|
|
15
17
|
return soup
|
|
16
18
|
|
|
17
|
-
|
|
19
|
+
|
|
20
|
+
class TestFields:
|
|
21
|
+
|
|
22
|
+
def setup_method(self):
|
|
23
|
+
setup_method()
|
|
18
24
|
|
|
19
25
|
def test_text_field(self):
|
|
20
26
|
w = self.ew.InputField(id="w", name='foo')
|
|
@@ -34,7 +40,8 @@ class _TestFields(TestCase):
|
|
|
34
40
|
w = self.ew.InputField(
|
|
35
41
|
name='foo',
|
|
36
42
|
validator=fev.UnicodeString(min=2))
|
|
37
|
-
|
|
43
|
+
with pytest.raises(fe.Invalid):
|
|
44
|
+
w.to_python('x', None)
|
|
38
45
|
assert isinstance(ew.widget_context.validation_error, fe.Invalid)
|
|
39
46
|
|
|
40
47
|
def test_html_field(self):
|
|
@@ -48,10 +55,72 @@ class _TestFields(TestCase):
|
|
|
48
55
|
text = fld.display(value=5)
|
|
49
56
|
assert soup('<a href="/foo/5/">Bar</a>') == soup(text), text
|
|
50
57
|
|
|
51
|
-
|
|
58
|
+
ew = ew.jinja2_ew
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def test_link_field(self):
|
|
62
|
+
text = self.ew.LinkField().display(value='/foo/5/')
|
|
63
|
+
assert '<a href="/foo/5/">/foo/5/</a>' == text
|
|
64
|
+
|
|
65
|
+
expected = '<a href="/foo">bar</a>'
|
|
66
|
+
assert expected == self.ew.LinkField(href='/foo').display(value='bar')
|
|
67
|
+
assert expected == self.ew.LinkField(text='bar').display(value='/foo')
|
|
68
|
+
assert expected == self.ew.LinkField().display(value=dict(href='/foo', text='bar'))
|
|
69
|
+
assert expected == self.ew.LinkField(label='bar').display(value=dict(href='/foo'))
|
|
70
|
+
assert expected == self.ew.LinkField(href='/foo').display(value=dict(text='bar'))
|
|
71
|
+
assert expected == self.ew.LinkField(attrs={'href':'/foo'}).display(value='bar')
|
|
72
|
+
assert expected == self.ew.LinkField(plaintext_if_no_href=True).display(value=dict(href='/foo', text='bar'))
|
|
73
|
+
assert expected == self.ew.LinkField(plaintext_if_no_href=True).display(href='/foo', value='bar')
|
|
74
|
+
|
|
75
|
+
def test_link_plaintext(self):
|
|
76
|
+
expected = 'bar'
|
|
77
|
+
assert expected == self.ew.LinkField(plaintext_if_no_href=True).display(value=dict(text='bar'))
|
|
78
|
+
assert expected == self.ew.LinkField(plaintext_if_no_href=True, label='bar').display(value=dict())
|
|
79
|
+
assert expected == self.ew.LinkField(plaintext_if_no_href=True, label='foo').display(value='bar')
|
|
80
|
+
|
|
81
|
+
def test_link_escaping(self):
|
|
82
|
+
text = '<script>alert("foo")</script>'
|
|
83
|
+
href = '" onclick="alert(\'foo\')'
|
|
84
|
+
expected = '<a ><script>alert("foo")</script></a>'
|
|
85
|
+
assert expected == self.ew.LinkField().display(text=text)
|
|
86
|
+
assert expected == self.ew.LinkField().display(text=text, value={})
|
|
87
|
+
assert expected == self.ew.LinkField().display(label=text)
|
|
88
|
+
assert expected == self.ew.LinkField().display(label=text, value={})
|
|
89
|
+
assert expected == self.ew.LinkField().display(value={'text':text})
|
|
90
|
+
assert expected == self.ew.LinkField(text=text).display()
|
|
91
|
+
assert expected == self.ew.LinkField(text=text).display(value={})
|
|
92
|
+
assert expected == self.ew.LinkField(label=text).display()
|
|
93
|
+
assert expected == self.ew.LinkField(label=text).display(value={})
|
|
94
|
+
assert expected == self.ew.LinkField(value={'text':text}).display()
|
|
95
|
+
expected = '<a href="<script>alert("foo")</script>"><script>alert("foo")</script></a>'
|
|
96
|
+
assert expected == self.ew.LinkField().display(value=text)
|
|
97
|
+
assert expected == self.ew.LinkField(value=text).display()
|
|
98
|
+
expected = '<a href="" onclick="alert('foo')">None</a>'
|
|
99
|
+
assert expected == self.ew.LinkField().display(href=href)
|
|
100
|
+
assert expected == self.ew.LinkField().display(href=href, value={})
|
|
101
|
+
assert expected == self.ew.LinkField().display(attrs={'href':href})
|
|
102
|
+
assert expected == self.ew.LinkField().display(attrs={'href':href}, value={})
|
|
103
|
+
assert expected == self.ew.LinkField().display(value={'href':href})
|
|
104
|
+
assert expected == self.ew.LinkField(href=href).display()
|
|
105
|
+
assert expected == self.ew.LinkField(href=href).display(value={})
|
|
106
|
+
assert expected == self.ew.LinkField(attrs={'href':href}).display()
|
|
107
|
+
assert expected == self.ew.LinkField(attrs={'href':href}).display(value={})
|
|
108
|
+
assert expected == self.ew.LinkField(value={'href':href}).display()
|
|
109
|
+
expected = '<script>alert("foo")</script>'
|
|
110
|
+
assert expected == self.ew.LinkField(plaintext_if_no_href=True).display(text=text)
|
|
111
|
+
assert expected == self.ew.LinkField(plaintext_if_no_href=True).display(label=text)
|
|
112
|
+
assert expected == self.ew.LinkField(plaintext_if_no_href=True).display(value=text)
|
|
113
|
+
assert expected == self.ew.LinkField(plaintext_if_no_href=True).display(value={'text':text})
|
|
114
|
+
assert expected == self.ew.LinkField(plaintext_if_no_href=True, label=text).display()
|
|
115
|
+
assert expected == self.ew.LinkField(plaintext_if_no_href=True, text=text).display()
|
|
116
|
+
assert expected == self.ew.LinkField(plaintext_if_no_href=True, value=text).display()
|
|
117
|
+
assert expected == self.ew.LinkField(plaintext_if_no_href=True, value={'text':text}).display()
|
|
52
118
|
|
|
53
|
-
|
|
54
|
-
|
|
119
|
+
|
|
120
|
+
class TestFieldSet:
|
|
121
|
+
|
|
122
|
+
def setup_method(self):
|
|
123
|
+
setup_method()
|
|
55
124
|
self.w = self.ew.FieldSet(
|
|
56
125
|
id="w",
|
|
57
126
|
fields=[
|
|
@@ -87,7 +156,8 @@ class _TestFieldSet(TestCase):
|
|
|
87
156
|
assert '<input id="w.bar" name="bar" value="baz"' in text
|
|
88
157
|
|
|
89
158
|
def test_validation(self):
|
|
90
|
-
|
|
159
|
+
with pytest.raises(fe.Invalid):
|
|
160
|
+
self.w.to_python(dict(foo='x', bar='xxy'), None)
|
|
91
161
|
assert isinstance(ew.widget_context.validation_error, fe.Invalid)
|
|
92
162
|
text = self.w.display()
|
|
93
163
|
assert '<label for="w.foo"' in text, text
|
|
@@ -104,18 +174,21 @@ class _TestFieldSet(TestCase):
|
|
|
104
174
|
assert '<input id="w.fs.foo" name="fs.foo" value="bar"' in text
|
|
105
175
|
|
|
106
176
|
def test_nested_validation(self):
|
|
107
|
-
|
|
108
|
-
|
|
177
|
+
with pytest.raises(fe.Invalid):
|
|
178
|
+
self.nested_w.to_python(dict(fs=dict(foo='x')), None)
|
|
109
179
|
assert isinstance(ew.widget_context.validation_error, fe.Invalid)
|
|
110
180
|
text = self.nested_w.display()
|
|
111
181
|
assert '<label for="w.fs.foo"' in text
|
|
112
182
|
assert '<span class="fielderror"' in text
|
|
113
183
|
assert '<input id="w.fs.foo" name="fs.foo" value="x"' in text
|
|
114
184
|
|
|
115
|
-
|
|
185
|
+
ew = ew.jinja2_ew
|
|
186
|
+
|
|
116
187
|
|
|
117
|
-
|
|
118
|
-
|
|
188
|
+
class TestRowField:
|
|
189
|
+
|
|
190
|
+
def setup_method(self):
|
|
191
|
+
setup_method()
|
|
119
192
|
self.w = self.ew.RowField(
|
|
120
193
|
id="w-row",
|
|
121
194
|
fields=[
|
|
@@ -134,16 +207,20 @@ class _TestRowField(TestCase):
|
|
|
134
207
|
assert '<input id="w-row.a" name="a" value="bar"' in text
|
|
135
208
|
|
|
136
209
|
def test_validation(self):
|
|
137
|
-
|
|
210
|
+
with pytest.raises(fe.Invalid):
|
|
211
|
+
self.w.to_python(dict(a='x', b='xx'), None)
|
|
138
212
|
assert isinstance(ew.widget_context.validation_error, fe.Invalid)
|
|
139
213
|
text = self.w.display()
|
|
140
214
|
assert '<span class="fielderror"' in text
|
|
141
215
|
assert '<input id="w-row.a" name="a" value="x"' in text, text
|
|
142
216
|
|
|
143
|
-
|
|
217
|
+
ew = ew.jinja2_ew
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
class TestRepeatedField:
|
|
144
221
|
|
|
145
|
-
def
|
|
146
|
-
|
|
222
|
+
def setup_method(self):
|
|
223
|
+
setup_method()
|
|
147
224
|
self.w = self.ew.RepeatedField(
|
|
148
225
|
id='w-a',
|
|
149
226
|
field=self.ew.InputField(
|
|
@@ -160,17 +237,20 @@ class _TestRepeatedField(TestCase):
|
|
|
160
237
|
assert '<input id="w-a-1" name="a-1"' not in text
|
|
161
238
|
|
|
162
239
|
def test_validation(self):
|
|
163
|
-
|
|
240
|
+
with pytest.raises(fe.Invalid):
|
|
241
|
+
self.w.to_python(['x', 'xx'], None)
|
|
164
242
|
assert isinstance(ew.widget_context.validation_error, fe.Invalid)
|
|
165
243
|
text = self.w.display(value=['xxx', 'xxx'])
|
|
166
244
|
assert '<span class="fielderror"' in text
|
|
167
245
|
assert '<input id="w-a-0" name="a-0" value="x"' in text, text
|
|
168
246
|
|
|
247
|
+
ew = ew.jinja2_ew
|
|
169
248
|
|
|
170
|
-
class _TestTableField(TestCase):
|
|
171
249
|
|
|
172
|
-
|
|
173
|
-
|
|
250
|
+
class TestTableField:
|
|
251
|
+
|
|
252
|
+
def setup_method(self):
|
|
253
|
+
setup_method()
|
|
174
254
|
self.w = self.ew.TableField(
|
|
175
255
|
id="w-foo",
|
|
176
256
|
name='foo',
|
|
@@ -190,17 +270,19 @@ class _TestTableField(TestCase):
|
|
|
190
270
|
assert '<input id="w-foo-row-0.a" name="foo-0.a" value="xx">' in text, text
|
|
191
271
|
|
|
192
272
|
def test_validation(self):
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
None)
|
|
273
|
+
with pytest.raises(fe.Invalid):
|
|
274
|
+
self.w.to_python([dict(a='x', b='xx'),
|
|
275
|
+
dict(a='yy', b='yy')],
|
|
276
|
+
None)
|
|
198
277
|
assert isinstance(ew.widget_context.validation_error, fe.Invalid)
|
|
199
278
|
text = self.w.display()
|
|
200
279
|
assert '<span class="fielderror"' in text, text
|
|
201
280
|
assert '<input id="w-foo-row-0.a" name="foo-0.a" value="x">' in text, text
|
|
202
281
|
|
|
203
|
-
|
|
282
|
+
ew = ew.jinja2_ew
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
class TestInputFields:
|
|
204
286
|
|
|
205
287
|
def test_text_field(self):
|
|
206
288
|
t = self.ew.TextField(id="w-foo", name='foo')
|
|
@@ -209,34 +291,43 @@ class _TestInputFields(TestCase):
|
|
|
209
291
|
def test_email_field(self):
|
|
210
292
|
t = self.ew.EmailField(id="w-foo", name='foo')
|
|
211
293
|
assert t.display() == '<input id="w-foo" name="foo" type="text">'
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
294
|
+
with pytest.raises(fe.Invalid):
|
|
295
|
+
t.to_python('asdf', None)
|
|
296
|
+
with pytest.raises(fe.Invalid):
|
|
297
|
+
t.to_python('asdf@bar', None)
|
|
298
|
+
with pytest.raises(fe.Invalid):
|
|
299
|
+
t.to_python('asdf@bar@bar.com', None)
|
|
215
300
|
t.to_python('foo@bar.com', None)
|
|
216
301
|
|
|
217
302
|
def test_int_field(self):
|
|
218
303
|
t = self.ew.IntField(id="w-foo", name='foo')
|
|
219
304
|
assert t.display() == '<input id="w-foo" name="foo" type="text">'
|
|
220
|
-
|
|
221
|
-
|
|
305
|
+
with pytest.raises(fe.Invalid):
|
|
306
|
+
t.to_python('asdf', None)
|
|
307
|
+
with pytest.raises(fe.Invalid):
|
|
308
|
+
t.to_python('42.5', None)
|
|
222
309
|
assert 42 == t.to_python('42', None)
|
|
223
310
|
|
|
224
311
|
def test_date_field(self):
|
|
225
312
|
t = self.ew.DateField(id="w-foo", name='foo')
|
|
226
313
|
text = t.display()
|
|
227
314
|
assert soup(text) == soup('<input id="w-foo" name="foo" type="text" style="width:6em">'), text
|
|
228
|
-
|
|
229
|
-
|
|
315
|
+
with pytest.raises(fe.Invalid):
|
|
316
|
+
t.to_python('asdf', None)
|
|
317
|
+
with pytest.raises(fe.Invalid):
|
|
318
|
+
t.to_python('1990.01.32', None)
|
|
230
319
|
assert date(1990, 1, 1) == t.to_python('01/01/1990', None)
|
|
231
320
|
|
|
232
321
|
def test_time_field(self):
|
|
233
322
|
t = self.ew.TimeField(id="w-foo", name='foo')
|
|
234
323
|
text = t.display()
|
|
235
324
|
assert soup(text) == soup('<input id="w-foo" name="foo" style="width:5em" type="text">'), soup(text)
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
325
|
+
with pytest.raises(fe.Invalid):
|
|
326
|
+
t.to_python('asdf', None)
|
|
327
|
+
with pytest.raises(fe.Invalid):
|
|
328
|
+
t.to_python('01:67', None)
|
|
329
|
+
assert time(1, 34) == t.to_python('1:34', None)
|
|
330
|
+
assert time(13, 34) == t.to_python('1:34 pm', None)
|
|
240
331
|
|
|
241
332
|
def test_textarea(self):
|
|
242
333
|
t = self.ew.TextArea(id="w-foo", name='foo', value="<script/>")
|
|
@@ -263,7 +354,10 @@ class _TestInputFields(TestCase):
|
|
|
263
354
|
assert (soup(text)==soup('<input name="foo" '
|
|
264
355
|
'value="Bar" type="submit" class="submit">')), text
|
|
265
356
|
|
|
266
|
-
|
|
357
|
+
ew = ew.jinja2_ew
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
class TestSelectFields:
|
|
267
361
|
|
|
268
362
|
def test_single_select(self):
|
|
269
363
|
for optlist in [
|
|
@@ -290,7 +384,6 @@ class _TestSelectFields(TestCase):
|
|
|
290
384
|
assert '<option value="b">' in text, text
|
|
291
385
|
assert '<script>alert(1)</script>' in text, text
|
|
292
386
|
|
|
293
|
-
|
|
294
387
|
def test_multi_select(self):
|
|
295
388
|
for optlist in [
|
|
296
389
|
'abc',
|
|
@@ -330,10 +423,13 @@ class _TestSelectFields(TestCase):
|
|
|
330
423
|
assert '<input checked name="foo" type="checkbox" value="b">' in text, text
|
|
331
424
|
assert '<input checked name="foo" type="checkbox" value="c">' in text, text
|
|
332
425
|
|
|
333
|
-
|
|
426
|
+
ew = ew.jinja2_ew
|
|
427
|
+
|
|
334
428
|
|
|
335
|
-
|
|
336
|
-
|
|
429
|
+
class TestForms:
|
|
430
|
+
|
|
431
|
+
def setup_method(self):
|
|
432
|
+
setup_method()
|
|
337
433
|
self.w = self.ew.SimpleForm(
|
|
338
434
|
id="w-foo",
|
|
339
435
|
fields=[
|
|
@@ -356,7 +452,8 @@ class _TestForms(TestCase):
|
|
|
356
452
|
assert '<input id="w-foo.bar" name="bar" value="baz"' in text
|
|
357
453
|
|
|
358
454
|
def test_validation(self):
|
|
359
|
-
|
|
455
|
+
with pytest.raises(fe.Invalid):
|
|
456
|
+
self.w.to_python(dict(foo='x', bar='xxy'), None)
|
|
360
457
|
assert isinstance(ew.widget_context.validation_error, fe.Invalid)
|
|
361
458
|
text = self.w.display()
|
|
362
459
|
assert '<label for="w-foo.foo"' in text, text
|
|
@@ -364,71 +461,4 @@ class _TestForms(TestCase):
|
|
|
364
461
|
assert '<input id="w-foo.foo" name="foo" value="x"' in text
|
|
365
462
|
assert '<input id="w-foo.bar" name="bar" value="xxy"' in text
|
|
366
463
|
|
|
367
|
-
|
|
368
|
-
class TestRowFieldJinja2(_TestRowField): ew=ew.jinja2_ew
|
|
369
|
-
class TestRepeatedFieldJinja2(_TestRepeatedField): ew=ew.jinja2_ew
|
|
370
|
-
class TestTableFieldJinja2(_TestTableField): ew=ew.jinja2_ew
|
|
371
|
-
class TestInputFieldsJinja2(_TestInputFields): ew=ew.jinja2_ew
|
|
372
|
-
class TestSelectFieldsJinja2(_TestSelectFields): ew=ew.jinja2_ew
|
|
373
|
-
class TestFormsJinja2(_TestForms): ew=ew.jinja2_ew
|
|
374
|
-
|
|
375
|
-
class TestFieldsJinja2(_TestFields):
|
|
376
|
-
ew=ew.jinja2_ew
|
|
377
|
-
|
|
378
|
-
def test_link_field(self):
|
|
379
|
-
text = self.ew.LinkField().display(value='/foo/5/')
|
|
380
|
-
self.assertEqual('<a href="/foo/5/">/foo/5/</a>', text)
|
|
381
|
-
|
|
382
|
-
expected = '<a href="/foo">bar</a>'
|
|
383
|
-
self.assertEqual(expected, self.ew.LinkField(href='/foo').display(value='bar'))
|
|
384
|
-
self.assertEqual(expected, self.ew.LinkField(text='bar').display(value='/foo'))
|
|
385
|
-
self.assertEqual(expected, self.ew.LinkField().display(value=dict(href='/foo', text='bar')))
|
|
386
|
-
self.assertEqual(expected, self.ew.LinkField(label='bar').display(value=dict(href='/foo')))
|
|
387
|
-
self.assertEqual(expected, self.ew.LinkField(href='/foo').display(value=dict(text='bar')))
|
|
388
|
-
self.assertEqual(expected, self.ew.LinkField(attrs={'href':'/foo'}).display(value='bar'))
|
|
389
|
-
self.assertEqual(expected, self.ew.LinkField(plaintext_if_no_href=True).display(value=dict(href='/foo', text='bar')))
|
|
390
|
-
self.assertEqual(expected, self.ew.LinkField(plaintext_if_no_href=True).display(href='/foo', value='bar'))
|
|
391
|
-
|
|
392
|
-
def test_link_plaintext(self):
|
|
393
|
-
expected = 'bar'
|
|
394
|
-
self.assertEqual(expected, self.ew.LinkField(plaintext_if_no_href=True).display(value=dict(text='bar')))
|
|
395
|
-
self.assertEqual(expected, self.ew.LinkField(plaintext_if_no_href=True, label='bar').display(value=dict()))
|
|
396
|
-
self.assertEqual(expected, self.ew.LinkField(plaintext_if_no_href=True, label='foo').display(value='bar'))
|
|
397
|
-
|
|
398
|
-
def test_link_escaping(self):
|
|
399
|
-
text = '<script>alert("foo")</script>'
|
|
400
|
-
href = '" onclick="alert(\'foo\')'
|
|
401
|
-
expected = '<a ><script>alert("foo")</script></a>'
|
|
402
|
-
self.assertEqual(expected, self.ew.LinkField().display(text=text))
|
|
403
|
-
self.assertEqual(expected, self.ew.LinkField().display(text=text, value={}))
|
|
404
|
-
self.assertEqual(expected, self.ew.LinkField().display(label=text))
|
|
405
|
-
self.assertEqual(expected, self.ew.LinkField().display(label=text, value={}))
|
|
406
|
-
self.assertEqual(expected, self.ew.LinkField().display(value={'text':text}))
|
|
407
|
-
self.assertEqual(expected, self.ew.LinkField(text=text).display())
|
|
408
|
-
self.assertEqual(expected, self.ew.LinkField(text=text).display(value={}))
|
|
409
|
-
self.assertEqual(expected, self.ew.LinkField(label=text).display())
|
|
410
|
-
self.assertEqual(expected, self.ew.LinkField(label=text).display(value={}))
|
|
411
|
-
self.assertEqual(expected, self.ew.LinkField(value={'text':text}).display())
|
|
412
|
-
expected = '<a href="<script>alert("foo")</script>"><script>alert("foo")</script></a>'
|
|
413
|
-
self.assertEqual(expected, self.ew.LinkField().display(value=text))
|
|
414
|
-
self.assertEqual(expected, self.ew.LinkField(value=text).display())
|
|
415
|
-
expected = '<a href="" onclick="alert('foo')">None</a>'
|
|
416
|
-
self.assertEqual(expected, self.ew.LinkField().display(href=href))
|
|
417
|
-
self.assertEqual(expected, self.ew.LinkField().display(href=href, value={}))
|
|
418
|
-
self.assertEqual(expected, self.ew.LinkField().display(attrs={'href':href}))
|
|
419
|
-
self.assertEqual(expected, self.ew.LinkField().display(attrs={'href':href}, value={}))
|
|
420
|
-
self.assertEqual(expected, self.ew.LinkField().display(value={'href':href}))
|
|
421
|
-
self.assertEqual(expected, self.ew.LinkField(href=href).display())
|
|
422
|
-
self.assertEqual(expected, self.ew.LinkField(href=href).display(value={}))
|
|
423
|
-
self.assertEqual(expected, self.ew.LinkField(attrs={'href':href}).display())
|
|
424
|
-
self.assertEqual(expected, self.ew.LinkField(attrs={'href':href}).display(value={}))
|
|
425
|
-
self.assertEqual(expected, self.ew.LinkField(value={'href':href}).display())
|
|
426
|
-
expected = '<script>alert("foo")</script>'
|
|
427
|
-
self.assertEqual(expected, self.ew.LinkField(plaintext_if_no_href=True).display(text=text))
|
|
428
|
-
self.assertEqual(expected, self.ew.LinkField(plaintext_if_no_href=True).display(label=text))
|
|
429
|
-
self.assertEqual(expected, self.ew.LinkField(plaintext_if_no_href=True).display(value=text))
|
|
430
|
-
self.assertEqual(expected, self.ew.LinkField(plaintext_if_no_href=True).display(value={'text':text}))
|
|
431
|
-
self.assertEqual(expected, self.ew.LinkField(plaintext_if_no_href=True, label=text).display())
|
|
432
|
-
self.assertEqual(expected, self.ew.LinkField(plaintext_if_no_href=True, text=text).display())
|
|
433
|
-
self.assertEqual(expected, self.ew.LinkField(plaintext_if_no_href=True, value=text).display())
|
|
434
|
-
self.assertEqual(expected, self.ew.LinkField(plaintext_if_no_href=True, value={'text':text}).display())
|
|
464
|
+
ew = ew.jinja2_ew
|
|
@@ -6,9 +6,10 @@ from webtest import TestApp
|
|
|
6
6
|
|
|
7
7
|
from ew import widget_context, Snippet, WidgetMiddleware, Widget
|
|
8
8
|
from ew import ResourceManager
|
|
9
|
-
from ew.tests.helpers import
|
|
9
|
+
from ew.tests.helpers import REGISTRY
|
|
10
10
|
|
|
11
11
|
import ew.jinja2_ew
|
|
12
|
+
import pytest
|
|
12
13
|
|
|
13
14
|
TEMPLATE = Snippet('''<html>
|
|
14
15
|
<head>
|
|
@@ -24,9 +25,9 @@ TEMPLATE = Snippet('''<html>
|
|
|
24
25
|
</html>''', 'jinja2')
|
|
25
26
|
|
|
26
27
|
|
|
27
|
-
class
|
|
28
|
+
class TestResourceInclusion:
|
|
28
29
|
|
|
29
|
-
def
|
|
30
|
+
def setup_method(self):
|
|
30
31
|
self.w = Widget(
|
|
31
32
|
template=Snippet('<h1>My Widget</h1>'),
|
|
32
33
|
resources=lambda:[
|
|
@@ -37,6 +38,7 @@ class _TestResourceInclusion(TestCase):
|
|
|
37
38
|
self.ew.JSScript('/* body_tail */', 'body_js_tail')
|
|
38
39
|
])
|
|
39
40
|
self.app = TestApp(_WidgetTest(self.w))
|
|
41
|
+
ew = ew.jinja2_ew
|
|
40
42
|
|
|
41
43
|
def test_render(self):
|
|
42
44
|
res = self.app.get('/')
|
|
@@ -60,9 +62,10 @@ class _TestResourceInclusion(TestCase):
|
|
|
60
62
|
for part in parts:
|
|
61
63
|
assert part in res, f'{part} not in {res}'
|
|
62
64
|
|
|
63
|
-
class _TestScripts(TestCase):
|
|
64
65
|
|
|
65
|
-
|
|
66
|
+
class TestScripts:
|
|
67
|
+
|
|
68
|
+
def setup_method(self):
|
|
66
69
|
self.resources = [
|
|
67
70
|
self.ew.JSLink('a/foo.js'),
|
|
68
71
|
self.ew.JSLink('a/bar.js'),
|
|
@@ -75,6 +78,8 @@ class _TestScripts(TestCase):
|
|
|
75
78
|
self.wtest = _WidgetTest(self.w)
|
|
76
79
|
self.app = TestApp(self.wtest)
|
|
77
80
|
|
|
81
|
+
ew = ew.jinja2_ew
|
|
82
|
+
|
|
78
83
|
def test_render(self):
|
|
79
84
|
app = TestApp(_WidgetTest(self.w))
|
|
80
85
|
res = app.get('/')
|
|
@@ -126,10 +131,14 @@ class _TestScripts(TestCase):
|
|
|
126
131
|
res = app.get('/_ew_resources/_slim/js?href=a%2Ftest-utf8.js')
|
|
127
132
|
assert 'ƒ∂ß' in res.text
|
|
128
133
|
|
|
134
|
+
app.get('/_ew_resources/_slim/js') # no param
|
|
135
|
+
app.get('/_ew_resources/_slim/js?href=foo;bar;;baz') # bad params
|
|
136
|
+
|
|
129
137
|
def test_reregister(self):
|
|
130
138
|
ResourceManager.register_directory('a', 'foo')
|
|
131
139
|
ResourceManager.register_directory('a', 'foo')
|
|
132
|
-
|
|
140
|
+
with pytest.raises(AssertionError):
|
|
141
|
+
ResourceManager.register_directory('a', 'bar')
|
|
133
142
|
|
|
134
143
|
def test_incompressible(self):
|
|
135
144
|
self.resources.append(self.ew.JSLink('a/baz.js', compress=False))
|
|
@@ -139,8 +148,6 @@ class _TestScripts(TestCase):
|
|
|
139
148
|
'a%2Ffoo.js%3Ba%2Fbar.js"') in res, res
|
|
140
149
|
assert 'src="/_ew_resources/a/baz.js"' in res, res
|
|
141
150
|
|
|
142
|
-
class TestResourceInclusionJinja2(_TestResourceInclusion): ew=ew.jinja2_ew
|
|
143
|
-
class TestScriptsJinja2(_TestScripts): ew=ew.jinja2_ew
|
|
144
151
|
|
|
145
152
|
class _WidgetTest:
|
|
146
153
|
|
|
@@ -162,14 +169,12 @@ class _WidgetTest:
|
|
|
162
169
|
resource_manager=widget_context.resource_manager))
|
|
163
170
|
return res(environ, start_response)
|
|
164
171
|
|
|
165
|
-
class TestResourceSecurity
|
|
172
|
+
class TestResourceSecurity:
|
|
166
173
|
|
|
167
|
-
def
|
|
174
|
+
def setup_method(self):
|
|
168
175
|
self.rm = ResourceManager()
|
|
169
176
|
self.rm.register_directory('res-test', '/a/b/c')
|
|
170
177
|
|
|
171
178
|
def test_cant_break_out(self):
|
|
172
|
-
self.
|
|
173
|
-
self.rm.get_filename('res-test/../etc/passwd'),
|
|
174
|
-
None)
|
|
179
|
+
assert self.rm.get_filename('res-test/../etc/passwd') == None
|
|
175
180
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
import pytest
|
|
2
2
|
|
|
3
3
|
from ew import utils
|
|
4
4
|
from ew import widget
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
class TestBunch:
|
|
7
8
|
|
|
8
9
|
def test_like_dict(self):
|
|
9
10
|
b = utils.Bunch(
|
|
@@ -19,14 +20,16 @@ class TestBunch(TestCase):
|
|
|
19
20
|
def test_invalid_getattr(self):
|
|
20
21
|
b = utils.Bunch(
|
|
21
22
|
foo=0, bar=1)
|
|
22
|
-
|
|
23
|
+
with pytest.raises(AttributeError):
|
|
24
|
+
getattr(b, 'baz')
|
|
23
25
|
|
|
24
26
|
def test_invalid_getitem(self):
|
|
25
27
|
b = utils.Bunch(
|
|
26
28
|
foo=0, bar=1)
|
|
27
|
-
|
|
29
|
+
pytest.raises(KeyError, b.__getitem__, 'baz')
|
|
30
|
+
|
|
28
31
|
|
|
29
|
-
class TestPushContext
|
|
32
|
+
class TestPushContext:
|
|
30
33
|
|
|
31
34
|
def test_push_context(self):
|
|
32
35
|
x = utils.Bunch(foo=1, bar=2)
|
|
@@ -35,11 +38,12 @@ class TestPushContext(TestCase):
|
|
|
35
38
|
assert x.bar == 2
|
|
36
39
|
assert x.baz == 0
|
|
37
40
|
assert x.foo == 1
|
|
38
|
-
|
|
41
|
+
pytest.raises(KeyError, x.__getitem__, 'baz')
|
|
39
42
|
|
|
40
|
-
class TestNameListAsClass(TestCase):
|
|
41
43
|
|
|
42
|
-
|
|
44
|
+
class TestNameListAsClass:
|
|
45
|
+
|
|
46
|
+
def setup_method(self):
|
|
43
47
|
class widgets(utils.NameList):
|
|
44
48
|
a=widget.Widget()
|
|
45
49
|
b=widget.Widget(name='boo')
|
|
@@ -48,16 +52,18 @@ class TestNameListAsClass(TestCase):
|
|
|
48
52
|
def test_widget_names(self):
|
|
49
53
|
assert self.widgets.a.name == 'a'
|
|
50
54
|
assert self.widgets.b.name == 'boo'
|
|
51
|
-
|
|
55
|
+
with pytest.raises(AttributeError):
|
|
56
|
+
getattr(self.widgets, 'c')
|
|
52
57
|
|
|
53
58
|
def test_widgets_by_index(self):
|
|
54
59
|
assert self.widgets[0] == self.widgets.a
|
|
55
60
|
assert self.widgets[1] == self.widgets.b
|
|
56
61
|
assert self.widgets == [ self.widgets.a, self.widgets.b ]
|
|
57
62
|
|
|
58
|
-
class TestWidgetListAsList(TestCase):
|
|
59
63
|
|
|
60
|
-
|
|
64
|
+
class TestWidgetListAsList:
|
|
65
|
+
|
|
66
|
+
def setup_method(self):
|
|
61
67
|
self.a = widget.Widget(name='a')
|
|
62
68
|
self.b = widget.Widget(name='b')
|
|
63
69
|
self.c = widget.Widget(name='c')
|
|
@@ -9,9 +9,9 @@ class Currency(fev.Number):
|
|
|
9
9
|
format='$%.2f'
|
|
10
10
|
store_factor=100
|
|
11
11
|
|
|
12
|
-
def
|
|
12
|
+
def to_python(self, value, state):
|
|
13
13
|
value = value.strip(' \r\n\t' + self.symbol)
|
|
14
|
-
return int(fev.Number.
|
|
14
|
+
return int(fev.Number.to_python(self, value, state) * self.store_factor)
|
|
15
15
|
|
|
16
16
|
def from_python(self, value, state):
|
|
17
17
|
if isinstance(value, str):
|
|
@@ -22,8 +22,8 @@ class Currency(fev.Number):
|
|
|
22
22
|
|
|
23
23
|
class TimeConverter(fev.TimeConverter):
|
|
24
24
|
|
|
25
|
-
def
|
|
26
|
-
value = super().
|
|
25
|
+
def to_python(self, value, state):
|
|
26
|
+
value = super().to_python(value, state)
|
|
27
27
|
if value is not None:
|
|
28
28
|
value = time(*value)
|
|
29
29
|
return value
|
|
@@ -47,7 +47,7 @@ class OneOf(fev.FancyValidator):
|
|
|
47
47
|
def __init__(self, options):
|
|
48
48
|
self.options = options
|
|
49
49
|
|
|
50
|
-
def
|
|
50
|
+
def _validate_python(self, value, state):
|
|
51
51
|
if callable(self.options):
|
|
52
52
|
options = self.options()
|
|
53
53
|
else:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from setuptools import setup, find_packages
|
|
2
2
|
|
|
3
|
-
version = '0.4'
|
|
3
|
+
version = '0.4.2'
|
|
4
4
|
|
|
5
5
|
setup(name='EasyWidgets',
|
|
6
6
|
version=version,
|
|
@@ -16,7 +16,12 @@ setup(name='EasyWidgets',
|
|
|
16
16
|
'Natural Language :: English',
|
|
17
17
|
'Operating System :: OS Independent',
|
|
18
18
|
'Programming Language :: Python',
|
|
19
|
-
'Programming Language :: Python :: 3.
|
|
19
|
+
'Programming Language :: Python :: 3.8',
|
|
20
|
+
'Programming Language :: Python :: 3.9',
|
|
21
|
+
'Programming Language :: Python :: 3.10',
|
|
22
|
+
'Programming Language :: Python :: 3.11',
|
|
23
|
+
'Programming Language :: Python :: 3.12',
|
|
24
|
+
|
|
20
25
|
],
|
|
21
26
|
keywords='TurboGears FormEncode TurboGears2',
|
|
22
27
|
author='Rick Copeland',
|
|
@@ -34,7 +39,7 @@ setup(name='EasyWidgets',
|
|
|
34
39
|
'public/*/*']},
|
|
35
40
|
include_package_data=True,
|
|
36
41
|
zip_safe=False,
|
|
37
|
-
python_requires='>=3.
|
|
42
|
+
python_requires='>=3.8',
|
|
38
43
|
install_requires=[
|
|
39
44
|
# -*- Extra requirements: -*-
|
|
40
45
|
'python-dateutil',
|
|
@@ -45,7 +50,7 @@ setup(name='EasyWidgets',
|
|
|
45
50
|
'six>=1.13.0',
|
|
46
51
|
],
|
|
47
52
|
tests_require=[
|
|
48
|
-
'
|
|
53
|
+
'pytest',
|
|
49
54
|
'webtest',
|
|
50
55
|
'bs4',
|
|
51
56
|
'jinja2',
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import unittest
|
|
2
|
-
|
|
3
|
-
from paste.registry import Registry
|
|
4
|
-
from ew import widget_context, TemplateEngine
|
|
5
|
-
from ew.core import WidgetContext
|
|
6
|
-
from ew.resource import ResourceManager
|
|
7
|
-
|
|
8
|
-
REGISTRY = Registry()
|
|
9
|
-
REGISTRY.prepare()
|
|
10
|
-
|
|
11
|
-
class TestCase(unittest.TestCase):
|
|
12
|
-
|
|
13
|
-
def setUp(self):
|
|
14
|
-
TemplateEngine.initialize({})
|
|
15
|
-
mgr = ResourceManager()
|
|
16
|
-
REGISTRY.register(
|
|
17
|
-
widget_context,
|
|
18
|
-
WidgetContext(scheme='http', resource_manager=mgr))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|