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.
Files changed (46) hide show
  1. {EasyWidgets-0.4 → easywidgets-0.4.2}/EasyWidgets.egg-info/PKG-INFO +16 -6
  2. easywidgets-0.4.2/EasyWidgets.egg-info/entry_points.txt +7 -0
  3. {EasyWidgets-0.4 → easywidgets-0.4.2}/PKG-INFO +16 -6
  4. {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/fields.py +2 -2
  5. {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/middleware.py +4 -3
  6. {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/resource.py +3 -1
  7. easywidgets-0.4.2/ew/tests/helpers.py +15 -0
  8. {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/tests/test_fields.py +142 -112
  9. {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/tests/test_resource.py +18 -13
  10. {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/tests/test_utils.py +17 -11
  11. {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/tests/test_widget.py +3 -3
  12. {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/validators.py +5 -5
  13. {EasyWidgets-0.4 → easywidgets-0.4.2}/setup.py +9 -4
  14. EasyWidgets-0.4/EasyWidgets.egg-info/entry_points.txt +0 -11
  15. EasyWidgets-0.4/ew/tests/helpers.py +0 -18
  16. {EasyWidgets-0.4 → easywidgets-0.4.2}/EasyWidgets.egg-info/SOURCES.txt +0 -0
  17. {EasyWidgets-0.4 → easywidgets-0.4.2}/EasyWidgets.egg-info/dependency_links.txt +0 -0
  18. {EasyWidgets-0.4 → easywidgets-0.4.2}/EasyWidgets.egg-info/not-zip-safe +0 -0
  19. {EasyWidgets-0.4 → easywidgets-0.4.2}/EasyWidgets.egg-info/requires.txt +0 -0
  20. {EasyWidgets-0.4 → easywidgets-0.4.2}/EasyWidgets.egg-info/top_level.txt +0 -0
  21. {EasyWidgets-0.4 → easywidgets-0.4.2}/MANIFEST.in +0 -0
  22. {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/__init__.py +0 -0
  23. {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/core.py +0 -0
  24. {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/errors.py +0 -0
  25. {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/forms.py +0 -0
  26. {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/jinja2_ew.py +0 -0
  27. {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/render.py +0 -0
  28. {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/select.py +0 -0
  29. {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/templates/__init__.py +0 -0
  30. {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/templates/jinja2/__init__.py +0 -0
  31. {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/templates/jinja2/_ew_lib.html +0 -0
  32. {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/templates/jinja2/checkbox.html +0 -0
  33. {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/templates/jinja2/checkbox_set.html +0 -0
  34. {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/templates/jinja2/field_set.html +0 -0
  35. {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/templates/jinja2/google_analytics.html +0 -0
  36. {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/templates/jinja2/repeated_field.html +0 -0
  37. {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/templates/jinja2/row_field.html +0 -0
  38. {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/templates/jinja2/select_field.html +0 -0
  39. {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/templates/jinja2/simple_form.html +0 -0
  40. {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/templates/jinja2/table_field.html +0 -0
  41. {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/tests/__init__.py +0 -0
  42. {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/tests/templates/__init__.py +0 -0
  43. {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/tests/templates/simple.html +0 -0
  44. {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/utils.py +0 -0
  45. {EasyWidgets-0.4 → easywidgets-0.4.2}/ew/widget.py +0 -0
  46. {EasyWidgets-0.4 → easywidgets-0.4.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 1.2
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.7
24
- Requires-Python: >=3.7
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.
@@ -0,0 +1,7 @@
1
+ [easy_widgets.engines]
2
+ core-ew = ew.render:CoreEngine
3
+ jinja2 = ew.render:Jinja2Engine
4
+ json = ew.render:JsonEngine
5
+
6
+ [paste.filter_factory]
7
+ easy_widgets = ew.middleware:paste_filter_factory
@@ -1,6 +1,6 @@
1
- Metadata-Version: 1.2
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.7
24
- Requires-Python: >=3.7
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 as e:
54
- warnings.warn('suppressed an error that you should probably fix. ' + traceback.format_exc(e),
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 cgi
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, cgi.parse_qs(environ['QUERY_STRING']).get('href', [''])[0],
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, cgi.parse_qs(environ['QUERY_STRING']).get('href', [''])[0],
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
- from ew.tests.helpers import TestCase
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
- class _TestFields(TestCase):
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
- self.assertRaises(fe.Invalid, w.to_python, 'x', None)
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
- class _TestFieldSet(TestCase):
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 >&lt;script&gt;alert(&#34;foo&#34;)&lt;/script&gt;</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="&lt;script&gt;alert(&#34;foo&#34;)&lt;/script&gt;">&lt;script&gt;alert(&#34;foo&#34;)&lt;/script&gt;</a>'
96
+ assert expected == self.ew.LinkField().display(value=text)
97
+ assert expected == self.ew.LinkField(value=text).display()
98
+ expected = '<a href="&#34; onclick=&#34;alert(&#39;foo&#39;)">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 = '&lt;script&gt;alert(&#34;foo&#34;)&lt;/script&gt;'
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
- def setUp(self):
54
- super().setUp()
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
- self.assertRaises(fe.Invalid, self.w.to_python, dict(foo='x', bar='xxy'), None)
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
- self.assertRaises(fe.Invalid, self.nested_w.to_python,
108
- dict(fs=dict(foo='x')), None)
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
- class _TestRowField(TestCase):
185
+ ew = ew.jinja2_ew
186
+
116
187
 
117
- def setUp(self):
118
- super().setUp()
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
- self.assertRaises(fe.Invalid, self.w.to_python, dict(a='x', b='xx'), None)
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
- class _TestRepeatedField(TestCase):
217
+ ew = ew.jinja2_ew
218
+
219
+
220
+ class TestRepeatedField:
144
221
 
145
- def setUp(self):
146
- super().setUp()
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
- self.assertRaises(fe.Invalid, self.w.to_python, ['x', 'xx'], None)
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
- def setUp(self):
173
- super().setUp()
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
- self.assertRaises(
194
- fe.Invalid, self.w.to_python,
195
- [ dict(a='x', b='xx'),
196
- dict(a='yy', b='yy')],
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
- class _TestInputFields(TestCase):
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
- self.assertRaises(fe.Invalid, t.to_python, 'asdf', None)
213
- self.assertRaises(fe.Invalid, t.to_python, 'asdf@bar', None)
214
- self.assertRaises(fe.Invalid, t.to_python, 'asdf@bar@bar.com', None)
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
- self.assertRaises(fe.Invalid, t.to_python, 'asdf', None)
221
- self.assertRaises(fe.Invalid, t.to_python, '42.5', None)
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
- self.assertRaises(fe.Invalid, t.to_python, 'asdf', None)
229
- self.assertRaises(fe.Invalid, t.to_python, '1990.01.32', None)
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
- self.assertRaises(fe.Invalid, t.to_python, 'asdf', None)
237
- self.assertRaises(fe.Invalid, t.to_python, '01:67', None)
238
- assert time(1,34) == t.to_python('1:34', None)
239
- assert time(13,34) == t.to_python('1:34 pm', None)
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
- class _TestSelectFields(TestCase):
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 '&lt;script&gt;alert(1)&lt;/script&gt;' 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
- class _TestForms(TestCase):
426
+ ew = ew.jinja2_ew
427
+
334
428
 
335
- def setUp(self):
336
- super().setUp()
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
- self.assertRaises(fe.Invalid, self.w.to_python, dict(foo='x', bar='xxy'), None)
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
- class TestFieldSetJinja2(_TestFieldSet): ew=ew.jinja2_ew
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 >&lt;script&gt;alert(&#34;foo&#34;)&lt;/script&gt;</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="&lt;script&gt;alert(&#34;foo&#34;)&lt;/script&gt;">&lt;script&gt;alert(&#34;foo&#34;)&lt;/script&gt;</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="&#34; onclick=&#34;alert(&#39;foo&#39;)">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 = '&lt;script&gt;alert(&#34;foo&#34;)&lt;/script&gt;'
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 TestCase, REGISTRY
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 _TestResourceInclusion(TestCase):
28
+ class TestResourceInclusion:
28
29
 
29
- def setUp(self):
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
- def setUp(self):
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
- self.assertRaises(AssertionError, ResourceManager.register_directory, 'a', 'bar')
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(TestCase):
172
+ class TestResourceSecurity:
166
173
 
167
- def setUp(self):
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.assertEqual(
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
- from unittest import TestCase
1
+ import pytest
2
2
 
3
3
  from ew import utils
4
4
  from ew import widget
5
5
 
6
- class TestBunch(TestCase):
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
- self.assertRaises(AttributeError, getattr, b, 'baz')
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
- self.assertRaises(KeyError, b.__getitem__, 'baz')
29
+ pytest.raises(KeyError, b.__getitem__, 'baz')
30
+
28
31
 
29
- class TestPushContext(TestCase):
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
- self.assertRaises(KeyError, x.__getitem__, 'baz')
41
+ pytest.raises(KeyError, x.__getitem__, 'baz')
39
42
 
40
- class TestNameListAsClass(TestCase):
41
43
 
42
- def setUp(self):
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
- self.assertRaises(AttributeError, getattr, self.widgets, 'c')
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
- def setUp(self):
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')
@@ -1,10 +1,10 @@
1
1
  import json
2
2
 
3
- from ew.tests.helpers import TestCase
4
- from ew import widget, errors, Snippet, File
3
+ from ew import widget, Snippet
5
4
 
6
5
 
7
- class TestWidget(TestCase):
6
+
7
+ class TestWidget:
8
8
 
9
9
  def test_json(self):
10
10
  w = widget.Widget(
@@ -9,9 +9,9 @@ class Currency(fev.Number):
9
9
  format='$%.2f'
10
10
  store_factor=100
11
11
 
12
- def _to_python(self, value, state):
12
+ def to_python(self, value, state):
13
13
  value = value.strip(' \r\n\t' + self.symbol)
14
- return int(fev.Number._to_python(self, value, state) * self.store_factor)
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 _to_python(self, value, state):
26
- value = super()._to_python(value, state)
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 validate_python(self, value, state):
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.7',
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.7',
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
- 'nose',
53
+ 'pytest',
49
54
  'webtest',
50
55
  'bs4',
51
56
  'jinja2',
@@ -1,11 +0,0 @@
1
-
2
- # -*- Entry points: -*-
3
- [easy_widgets.engines]
4
- json = ew.render:JsonEngine
5
- core-ew = ew.render:CoreEngine
6
- jinja2 = ew.render:Jinja2Engine
7
-
8
- [paste.filter_factory]
9
- easy_widgets = ew.middleware:paste_filter_factory
10
-
11
-
@@ -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