wcs/tests/test_fields.py

958 lines
35 KiB
Python

import json
import os
import re
import time
import pytest
import responses
from bs4 import BeautifulSoup
from quixote.http_request import Upload
from wcs import fields
from wcs.blocks import BlockDef
from wcs.data_sources import NamedDataSource
from wcs.formdef import FormDef
from wcs.qommon import sessions
from wcs.qommon.form import Form
from wcs.qommon.http_request import HTTPRequest
from wcs.qommon.substitution import CompatibilityNamesDict
from wcs.qommon.upload_storage import PicklableUpload
from wcs.variables import LazyFormData
from .utilities import MockSubstitutionVariables, clean_temporary_pub, create_temporary_pub
@pytest.fixture
def pub():
pub = create_temporary_pub()
req = HTTPRequest(None, {'SERVER_NAME': 'example.net', 'SCRIPT_NAME': ''})
pub._set_request(req)
req.session = sessions.Session(id=1)
return pub
def teardown_module(module):
clean_temporary_pub()
def test_fill_admin_form(pub):
pub.root_directory.backoffice = pub.backoffice_directory_class()
for klass in fields.field_classes:
form = Form(use_tokens=False)
klass().fill_admin_form(form)
def test_get_admin_attributes():
for klass in fields.field_classes:
klass().get_admin_attributes()
def test_add_to_form():
for klass in fields.field_classes:
form = Form(use_tokens=False)
if klass is fields.PageField:
with pytest.raises(AttributeError):
klass(label='foo').add_to_form(form)
elif klass is fields.ComputedField:
# no ui
continue
else:
klass(label='foo').add_to_form(form)
def test_convert_from_empty_string():
for klass in fields.field_classes:
field = klass(label='foo')
if field.convert_value_from_str:
assert bool(field.convert_value_from_str('')) is False
def test_string():
# sample string
assert fields.StringField().get_view_value('foo') == 'foo'
assert fields.StringField().get_view_short_value('foo') == 'foo'
assert fields.StringField().get_rst_view_value('foo') == 'foo'
assert fields.StringField().get_csv_value('foo') == ['foo']
# empty string
assert fields.StringField().get_view_value('') == ''
assert fields.StringField().get_view_short_value('') == ''
assert fields.StringField().get_rst_view_value('') == ''
assert fields.StringField().get_csv_value('') == ['']
# url
url = 'https://www.example.org/plop-plop-plop'
assert (
str(fields.StringField().get_view_value(url))
== '<a href="https://www.example.org/plop-plop-plop" rel="nofollow">https://www.example.org/plop-plop-plop</a>'
)
assert (
str(fields.StringField().get_view_short_value(url))
== '<a href="https://www.example.org/plop-plop-plop" rel="nofollow">https://www.example.org/plop-plop-plop</a>'
)
assert str(fields.StringField().get_rst_view_value(url)) == url
assert fields.StringField().get_csv_value(url) == [url]
# hackish url
url = 'https://www.example.org/"><script>plop</script>'
assert (
str(fields.StringField().get_view_value(url))
== '<a href="https://www.example.org/" rel="nofollow">https://www.example.org/</a>&quot;&gt;&lt;script&gt;plop&lt;/script&gt;'
)
assert (
str(fields.StringField().get_view_short_value(url))
== '<a href="https://www.example.org/" rel="nofollow">https://www.example.org/</a>&quot;&gt;&lt;script&gt;plop&lt;/script&gt;'
)
assert str(fields.StringField().get_rst_view_value(url)) == url
assert fields.StringField().get_csv_value(url) == [url]
def test_text(pub):
assert fields.TextField().get_view_short_value('foo' * 15) == ('foo' * 10)[:27] + '(…)'
assert fields.TextField().get_view_value('foo') == '<p>foo</p>'
assert fields.TextField().get_view_value('foo\n\nfoo') == '<p>foo\n</p><p>\nfoo</p>'
assert fields.TextField(display_mode='pre').get_view_value('foo') == '<p class="plain-text-pre">foo</p>'
assert (
fields.TextField(display_mode='rich').get_view_short_value('<p>foo</p>' * 15)
== ('foo' * 10)[:27] + '(…)'
)
assert fields.TextField(display_mode='rich').get_view_value('<script></script><p>foo</p>') == '<p>foo</p>'
form = Form(use_tokens=False)
fields.TextField().add_to_form(form)
assert '<textarea' in str(form.render())
assert 'cols="72"' in str(form.render())
assert 'rows="5"' in str(form.render())
form = Form(use_tokens=False)
fields.TextField(cols='12', rows='12').add_to_form(form)
assert '<textarea' in str(form.render())
assert 'cols="12"' in str(form.render())
assert 'rows="12"' in str(form.render())
def test_text_anonymise(pub):
formdef = FormDef()
formdef.name = 'title'
formdef.fields = [fields.TextField(id='0', label='comment', type='text', varname='comment')]
formdef.store()
formdata = formdef.data_class()()
formdata.just_created()
formdata.data = {'0': 'bar'}
formdata.anonymise()
assert not formdata.data.get('0')
formdef.fields[0].anonymise = False
formdef.store()
formdata = formdef.data_class()()
formdata.just_created()
formdata.data = {'0': 'bar'}
formdata.anonymise()
assert formdata.data.get('0') == 'bar'
def test_email():
assert (
fields.EmailField().get_view_value('foo@localhost')
== '<a href="mailto:foo@localhost">foo@localhost</a>'
)
assert fields.EmailField().get_rst_view_value('foo@localhost') == 'foo@localhost'
def test_bool():
assert fields.BoolField().get_view_value(True) == 'Yes'
assert fields.BoolField().get_view_value(False) == 'No'
def test_bool_stats():
formdef = FormDef()
formdef.name = 'title'
formdef.url_name = 'title'
formdef.fields = [fields.BoolField(id='1')]
formdef.store()
data_class = formdef.data_class()
formdatas = []
for value in (True, True, True, False):
formdata = data_class()
formdata.data = {'1': value}
formdatas.append(formdata)
stats = formdef.fields[0].stats(formdatas)
assert re.findall('Yes.*75.*No.*25', str(stats))
def test_items(pub):
assert fields.ItemsField(items=['a', 'b', 'c']).get_view_value(['a', 'b']) == 'a, b'
assert fields.ItemsField(items=['a', 'b', 'c']).get_csv_value(['a', 'b']) == ['a', 'b', '']
assert len(fields.ItemsField(items=['a', 'b', 'c']).get_csv_heading()) == 3
assert fields.ItemsField(items=['a', 'b', 'c'], max_choices=2).get_csv_value(['a', 'b']) == ['a', 'b']
assert len(fields.ItemsField(items=['a', 'b', 'c'], max_choices=2).get_csv_heading()) == 2
field = fields.ItemsField(label='plop')
field.data_source = {
'type': 'jsonvalue',
'value': '[{"id": "1", "text": "foo"}, {"id": "2", "text": "bar"}]',
}
assert field.get_options() == [('1', 'foo', '1'), ('2', 'bar', '2')]
assert field.get_options() == [('1', 'foo', '1'), ('2', 'bar', '2')] # twice for cached behaviour
assert field.get_csv_heading() == ['plop (identifier)', 'plop (label)', '(continued)', '(continued)']
assert field.get_csv_value(['a', 'b'], structured_value=json.loads(field.data_source['value'])) == [
'1',
'foo',
'2',
'bar',
]
# check values is cut on max choices
field.max_choices = 1
assert field.get_csv_heading() == ['plop (identifier)', 'plop (label)']
assert field.get_csv_value(['a', 'b'], structured_value=json.loads(field.data_source['value'])) == [
'1',
'foo',
]
# check empty columns are added if necessary
field._cached_data_source = None
field.max_choices = None
field.data_source[
'value'
] = '[{"id": "1", "text": "foo"}, {"id": "2", "text": "bar"}, {"id": "3", "text": "baz"}]'
assert field.get_csv_heading() == [
'plop (identifier)',
'plop (label)',
'(continued)',
'(continued)',
'(continued)',
'(continued)',
]
assert field.get_csv_value(['a', 'b'], structured_value=json.loads(field.data_source['value'])[:2]) == [
'1',
'foo',
'2',
'bar',
'',
'',
]
# if labels are available, display using <ul>
field = fields.ItemsField()
view_value = field.get_view_value('a, b', value_id=['1', '2'], labels=['a', 'b'])
elems = BeautifulSoup(str(view_value)).find('ul').find_all('li')
assert len(elems) == 2
assert elems[0].text == 'a'
assert elems[1].text == 'b'
def test_items_get_value_info():
# no data source : labels are available
field = fields.ItemsField(id='1', items=['a', 'b', 'c'])
assert field.get_value_info({'1': ['un', 'deux'], '1_display': 'un, deux'}) == (
'un, deux',
{'value_id': ['un', 'deux'], 'labels': ['un', 'deux']},
)
# data source with structured : labels are available
field = fields.ItemsField(id='1')
field.data_source = {
'type': 'jsonvalue',
'value': '[{"id": "1", "text": "foo"}, {"id": "2", "text": "bar"}]',
}
assert field.get_value_info(
{
'1': ['un', 'deux'],
'1_display': 'un, deux',
'1_structured': [{'id': '1', 'text': 'un'}, {'id': '2', 'text': 'deux'}],
}
) == (
'un, deux',
{'value_id': ['un', 'deux'], 'labels': ['un', 'deux']},
)
# data source with no strucured : no labels
field = fields.ItemsField(id='1')
field.data_source = {
'type': 'jsonvalue',
'value': '[{"id": "1", "text": "foo"}, {"id": "2", "text": "bar"}]',
}
assert field.get_value_info({'1': ['un', 'deux'], '1_display': 'un, deux'}) == (
'un, deux',
{'value_id': ['un', 'deux'], 'labels': []},
)
def test_password():
assert fields.PasswordField().get_view_value('xxx') == '' * 8
def test_file():
upload = Upload('/foo/bar', content_type='text/plain')
assert fields.FileField().get_csv_value(upload) == ['/foo/bar']
def test_page():
formdef = FormDef()
formdef.fields = []
page = fields.PageField()
assert page.is_visible({}, formdef) is True
page.condition = {'type': 'python', 'value': 'var_foo == "bar"'}
assert page.is_visible({}, formdef) is True # 'var_foo' is not defined
formdef.fields = [fields.StringField(id='1', label='string', varname='foo')]
assert page.is_visible({}, formdef) is False
assert page.is_visible({'1': 'bar'}, formdef) is True
assert page.is_visible({'1': 'baz'}, formdef) is False
def test_table():
assert 'prefill' not in fields.TableField().get_admin_attributes()
def test_title(pub):
field = fields.TitleField(label='Foobar')
form = Form(use_tokens=False)
field.add_to_form(form)
assert '<h3 data-field-id="None">Foobar</h3>' in str(form.render())
field = fields.TitleField(label='Foobar', extra_css_class='test')
form = Form(use_tokens=False)
field.add_to_form(form)
assert '<h3 data-field-id="None" class="test">Foobar</h3>' in str(form.render())
# test for variable substitution
pub.substitutions.feed(MockSubstitutionVariables())
field = fields.TitleField(label='{{ bar }}')
form = Form(use_tokens=False)
field.add_to_form(form)
assert '<h3 data-field-id="None">Foobar</h3>' in str(form.render())
pub.substitutions.feed(MockSubstitutionVariables())
field = fields.TitleField(label='[bar]')
form = Form(use_tokens=False)
field.add_to_form(form)
assert '<h3 data-field-id="None">Foobar</h3>' in str(form.render())
# test for proper escaping of substitution variables
pub.substitutions.feed(MockSubstitutionVariables())
field = fields.TitleField(label='{{ foo }}')
form = Form(use_tokens=False)
field.add_to_form(form)
assert '<h3 data-field-id="None">1 &lt; 3</h3>' in str(form.render())
pub.substitutions.feed(MockSubstitutionVariables())
field = fields.TitleField(label='[foo]')
form = Form(use_tokens=False)
field.add_to_form(form)
assert '<h3 data-field-id="None">1 &lt; 3</h3>' in str(form.render())
# test for html content
field = fields.TitleField(label='<i>Foobar&eacute;</i>')
form = Form(use_tokens=False)
field.add_to_form(form)
assert '&lt;i&gt;Foobar&amp;eacute;&lt;/i&gt;' in str(form.render())
assert field.unhtmled_label == 'Foobaré'
def test_subtitle(pub):
field = fields.SubtitleField(label='Foobar')
form = Form(use_tokens=False)
field.add_to_form(form)
assert '<h4 data-field-id="None">Foobar</h4>' in str(form.render())
field = fields.SubtitleField(label='Foobar', extra_css_class='test')
form = Form(use_tokens=False)
field.add_to_form(form)
assert '<h4 data-field-id="None" class="test">Foobar</h4>' in str(form.render())
# test for variable substitution
pub.substitutions.feed(MockSubstitutionVariables())
field = fields.SubtitleField(label='{{ bar }}')
form = Form(use_tokens=False)
field.add_to_form(form)
assert '<h4 data-field-id="None">Foobar</h4>' in str(form.render())
pub.substitutions.feed(MockSubstitutionVariables())
field = fields.SubtitleField(label='[bar]')
form = Form(use_tokens=False)
field.add_to_form(form)
assert '<h4 data-field-id="None">Foobar</h4>' in str(form.render())
# test for proper escaping of substitution variables
pub.substitutions.feed(MockSubstitutionVariables())
field = fields.SubtitleField(label='{{ foo }}')
form = Form(use_tokens=False)
field.add_to_form(form)
assert '<h4 data-field-id="None">1 &lt; 3</h4>' in str(form.render())
pub.substitutions.feed(MockSubstitutionVariables())
field = fields.SubtitleField(label='[foo]')
form = Form(use_tokens=False)
field.add_to_form(form)
assert '<h4 data-field-id="None">1 &lt; 3</h4>' in str(form.render())
# test for html content
field = fields.SubtitleField(label='<i>Foobar&eacute;</i>')
form = Form(use_tokens=False)
field.add_to_form(form)
assert '&lt;i&gt;Foobar&amp;eacute;&lt;/i&gt;' in str(form.render())
assert field.unhtmled_label == 'Foobaré'
def test_comment(pub):
field = fields.CommentField(label='Foobar')
form = Form(use_tokens=False)
field.add_to_form(form)
assert BeautifulSoup(str(form.render())).find('div').text.strip() == 'Foobar'
field = fields.CommentField(label='Foo\n\nBar\n\nBaz')
form = Form(use_tokens=False)
field.add_to_form(form)
assert re.match( # regex to handle different beautifulsoup behaviours
r'<div class="comment-field\s?">\n<p>Foo</p>\n<p>Bar</p>\n<p>Baz</p>\n</div>',
str(BeautifulSoup(str(form.render())).find('div')),
)
# test for variable substitution
pub.substitutions.feed(MockSubstitutionVariables())
field = fields.CommentField(label='{{ bar }}')
form = Form(use_tokens=False)
field.add_to_form(form)
assert BeautifulSoup(str(form.render())).find('div').text.strip() == 'Foobar'
field = fields.CommentField(label='[bar]')
form = Form(use_tokens=False)
field.add_to_form(form)
assert BeautifulSoup(str(form.render())).find('div').text.strip() == 'Foobar'
# test for proper escaping of substitution variables
field = fields.CommentField(label='{{ foo }}')
form = Form(use_tokens=False)
field.add_to_form(form)
assert '1 &lt; 3' in str(form.render())
field = fields.CommentField(label='[foo]')
form = Form(use_tokens=False)
field.add_to_form(form)
assert '1 &lt; 3' in str(form.render())
# test for html content
field = fields.CommentField(label='<p>Foobar</p>')
form = Form(use_tokens=False)
field.add_to_form(form)
assert '<p>Foobar</p>' in str(form.render())
assert field.unhtmled_label == 'Foobar'
field = fields.CommentField(label='<p>Foobar&eacute;</p>')
assert field.unhtmled_label == 'Foobaré'
def test_map():
assert fields.MapField().get_json_value('42.2;10.2') == {'lat': 42.2, 'lon': 10.2}
assert fields.MapField().get_json_value('-42.2;10.2') == {'lat': -42.2, 'lon': 10.2}
assert fields.MapField().get_json_value(' 42.2 ; 10.2 ') == {'lat': 42.2, 'lon': 10.2}
assert fields.MapField().get_json_value('') is None
assert fields.MapField().get_json_value('foobar') is None
def test_map_set_value(pub):
formdef = FormDef()
formdef.name = 'foobar'
formdef.fields = [fields.MapField(id='5', label='map', varname='map')]
formdef.store()
formdef.data_class().wipe()
formdata = formdef.data_class()()
formdata.data = {}
formdef.fields[0].set_value(formdata.data, '42;10')
assert formdata.data['5'] == '42;10'
substvars = CompatibilityNamesDict()
substvars.update(formdata.get_substitution_variables())
keys = substvars.get_flat_keys()
assert 'form_var_map_lon' in keys
assert 'form_var_map_lat' in keys
assert isinstance(substvars['form_var_map_lon'], float)
assert int(substvars['form_var_map_lon']) == 10
formdef.fields[0].set_value(formdata.data, '')
assert formdata.data['5'] is None
substvars = CompatibilityNamesDict()
substvars.update(formdata.get_substitution_variables())
keys = substvars.get_flat_keys()
assert 'form_var_map_lon' not in keys
# set invalid value, it is ignored
with pytest.raises(fields.SetValueError):
formdef.fields[0].set_value(formdata.data, 'XXX;YYY')
# set invalid value without using set_value()
formdata.data['5'] = 'XXX;YYY'
substvars = CompatibilityNamesDict()
substvars.update(formdata.get_substitution_variables())
keys = substvars.get_flat_keys()
assert 'form_var_map_lon' not in keys
def test_item_render():
items_kwargs = []
items_kwargs.append({'items': ['aa', 'ab', 'ac']})
items_kwargs.append(
{
'data_source': {
'type': 'jsonvalue',
'value': '[{"id": "aa", "text": "aa"}, {"id": "ab", "text": "ab"}, {"id": "ac", "text": "ac"}]',
}
}
)
for item_kwargs in items_kwargs:
field = fields.ItemField(id='1', label='Foobar', **item_kwargs)
form = Form(use_tokens=False)
field.add_to_form(form)
assert str(form.render()).count('<option') == 3
field = fields.ItemField(id='1', label='Foobar', required=False, **item_kwargs)
form = Form(use_tokens=False)
field.add_to_form(form)
assert str(form.render()).count('<option') == 3
field = fields.ItemField(id='1', label='Foobar', required=False, hint='Bla bla bla', **item_kwargs)
form = Form(use_tokens=False)
field.add_to_form(form)
assert (
str(form.render()).count('<option value="" data-hint="Bla bla bla">Bla bla bla</option>') == 1
) # ---
assert str(form.render()).count('<option') == 4
field = fields.ItemField(id='1', label='Foobar', required=True, hint='Bla bla bla', **item_kwargs)
form = Form(use_tokens=False)
field.add_to_form(form)
assert (
str(form.render()).count('<option value="" data-hint="Bla bla bla">Bla bla bla</option>') == 1
) # ---
assert str(form.render()).count('<option') == 4
items_kwargs = []
items_kwargs.append({'items': None})
items_kwargs.append({'items': []})
items_kwargs.append({'data_source': {'type': 'jsonvalue', 'value': '[]'}})
for item_kwargs in items_kwargs:
field = fields.ItemField(id='1', label='Foobar', **item_kwargs)
form = Form(use_tokens=False)
field.add_to_form(form)
assert str(form.render()).count('<option') == 1
field = fields.ItemField(id='1', label='Foobar', required=False, **item_kwargs)
form = Form(use_tokens=False)
field.add_to_form(form)
assert str(form.render()).count('<option') == 1
field = fields.ItemField(id='1', label='Foobar', required=False, hint='Bla bla bla', **item_kwargs)
form = Form(use_tokens=False)
field.add_to_form(form)
assert (
str(form.render()).count('<option value="" data-hint="Bla bla bla">Bla bla bla</option>') == 1
) # ---
assert str(form.render()).count('<option') == 1
field = fields.ItemField(id='1', label='Foobar', required=True, hint='Bla bla bla', **item_kwargs)
form = Form(use_tokens=False)
field.add_to_form(form)
assert (
str(form.render()).count('<option value="" data-hint="Bla bla bla">Bla bla bla</option>') == 1
) # ---
assert str(form.render()).count('<option') == 1
def test_item_render_as_autocomplete():
field = fields.ItemField(id='1', label='Foobar', items=['aa', 'ab', 'ac'], display_mode='autocomplete')
form = Form(use_tokens=False)
field.add_to_form(form)
assert str(form.render()).count('<option') == 3
assert 'data-autocomplete' in str(form.render())
def test_item_get_display_value(pub):
field = fields.ItemField(id='1', label='Foobar', items=['aa', 'ab', 'ac'], display_mode='autocomplete')
assert field.get_display_value('aa') == 'aa'
NamedDataSource.wipe()
data_source = NamedDataSource(name='foobar')
data_source.data_source = {'type': 'json', 'value': 'http://remote.example.net/json'}
data_source.query_parameter = 'q'
data_source.id_parameter = 'id'
data_source.store()
field.data_source = {'type': 'foobar'}
with responses.RequestsMock() as rsps:
rsps.get(
'http://remote.example.net/json',
json={'data': [{'id': '1', 'text': 'foo'}, {'id': '2', 'text': 'bar'}]},
)
assert field.get_display_value('aa') is None # no lookup on ?id=
# no crash if there's no session
pub.get_request().session = None
assert field.get_display_value('aa') is None
# with a url handling ?id
pub.get_request().datasources_cache = {}
rsps.get('http://remote.example.net/json?id=aa', json={'data': [{'id': 'aa', 'text': 'foo'}]})
assert field.get_display_value('aa') == 'foo'
# with numeric id
pub.get_request().datasources_cache = {}
rsps.get('http://remote.example.net/json?id=1', json={'data': [{'id': 1, 'text': 'foo'}]})
assert field.get_display_value(1) == 'foo'
# with None -> not a valid value
pub.get_request().datasources_cache = {}
assert field.get_display_value(None) is None
def test_item_render_as_radio():
items_kwargs = []
items_kwargs.append({'items': ['aa', 'ab', 'ac']})
items_kwargs.append(
{
'data_source': {
'type': 'jsonvalue',
'value': '[{"id": "aa", "text": "aa"}, {"id": "ab", "text": "ab"}, {"id": "ac", "text": "ac"}]',
}
}
)
for item_kwargs in items_kwargs:
field = fields.ItemField(id='1', label='Foobar', display_mode='radio', **item_kwargs)
form = Form(use_tokens=False)
field.add_to_form(form)
assert str(form.render()).count('"radio"') == 3
field = fields.ItemField(id='1', label='Foobar', required=False, display_mode='radio', **item_kwargs)
form = Form(use_tokens=False)
field.add_to_form(form)
assert str(form.render()).count('"radio"') == 3
field = fields.ItemField(
id='1', label='Foobar', display_mode='radio', required=False, hint='Bla bla bla', **item_kwargs
)
form = Form(use_tokens=False)
field.add_to_form(form)
assert str(form.render()).count('"radio"') == 3
field = fields.ItemField(
id='1', label='Foobar', display_mode='radio', required=True, hint='Bla bla bla', **item_kwargs
)
form = Form(use_tokens=False)
field.add_to_form(form)
assert str(form.render()).count('"radio"') == 3
items_kwargs = []
items_kwargs.append({'items': None})
items_kwargs.append({'items': []})
items_kwargs.append({'data_source': {'type': 'jsonvalue', 'value': '[]'}})
for item_kwargs in items_kwargs:
field = fields.ItemField(id='1', label='Foobar', display_mode='radio', **item_kwargs)
form = Form(use_tokens=False)
field.add_to_form(form)
assert str(form.render()).count('"radio"') == 1
field = fields.ItemField(id='1', label='Foobar', required=False, display_mode='radio', **item_kwargs)
form = Form(use_tokens=False)
field.add_to_form(form)
assert str(form.render()).count('"radio"') == 1
field = fields.ItemField(
id='1', label='Foobar', display_mode='radio', required=False, hint='Bla bla bla', **item_kwargs
)
form = Form(use_tokens=False)
field.add_to_form(form)
assert str(form.render()).count('"radio"') == 1
field = fields.ItemField(
id='1', label='Foobar', display_mode='radio', required=True, hint='Bla bla bla', **item_kwargs
)
form = Form(use_tokens=False)
field.add_to_form(form)
assert str(form.render()).count('"radio"') == 1
def test_item_radio_lengths():
field = fields.ItemField(id='1', label='Foobar', display_mode='radio', items=['aa', 'ab', 'ac'])
form = Form(use_tokens=False)
field.add_to_form(form)
form.render()
assert 'widget-inline-radio' in str(form.widgets[-1].render())
field = fields.ItemField(id='1', label='Foobar', display_mode='radio', items=['aa' * 30, 'ab', 'ac'])
form = Form(use_tokens=False)
field.add_to_form(form)
form.render()
assert 'widget-inline-radio' not in str(form.widgets[-1].render())
field = fields.ItemField(id='1', label='Foobar', display_mode='radio', items=['aa', 'ab' * 30, 'ac'])
form = Form(use_tokens=False)
field.add_to_form(form)
form.render()
assert 'widget-inline-radio' not in str(form.widgets[-1].render())
field = fields.ItemField(id='1', label='Foobar', display_mode='radio', items=['aa', 'ab', 'ac', 'ad'])
form = Form(use_tokens=False)
field.add_to_form(form)
form.render()
assert 'widget-inline-radio' not in str(form.widgets[-1].render())
def test_items_render():
items_kwargs = []
items_kwargs.append({'items': ['aa', 'ab', 'ac']})
items_kwargs.append(
{
'data_source': {
'type': 'jsonvalue',
'value': '[{"id": "aa", "text": "aa"}, {"id": "ab", "text": "ab"}, {"id": "ac", "text": "ac"}]',
}
}
)
for item_kwargs in items_kwargs:
field = fields.ItemsField(id='1', label='Foobar', **item_kwargs)
form = Form(use_tokens=False)
field.add_to_form(form)
assert str(form.render()).count('type="checkbox"') == 3
assert '>aa<' in str(form.render())
assert '>ab<' in str(form.render())
assert '>ac<' in str(form.render())
def test_ranked_items():
field = fields.RankedItemsField(id='1', label='Foobar', items=['aa', 'ab', 'ac'])
assert len(field.get_csv_heading()) == 3
assert field.get_csv_value({'aa': 2, 'ab': 1, 'ac': 3}) == ['ab', 'aa', 'ac']
def test_table_rows():
field = fields.TableRowsField(id='1', label='Foobar', columns=['aa', 'ab', 'ac'], total_row=False)
html_table = str(field.get_view_value([['A', 'B', 'C'], ['D', 'E', 'F']]))
assert html_table.count('<tr>') == 3
assert html_table.count('<th>') == 3
assert html_table.count('<td>') == 6
assert html_table.count('<tfoot>') == 0
for letter in 'ABCDEF':
assert '>%s<' % letter in html_table
rst_table = field.get_rst_view_value([['A', 'B', 'C'], ['D', 'E', 'F']])
assert rst_table.count('==') == 9
# check it doesn't crash when new columns are defined
html_table = str(field.get_view_value([['A', 'B'], ['D', 'E']]))
assert html_table.count('<tr>') == 3
assert html_table.count('<th>') == 3
assert html_table.count('<td>') == 6
for letter in 'ABDE':
assert '>%s<' % letter in html_table
assert html_table.count('<td></td>') == 2
rst_table = field.get_rst_view_value([['A', 'B'], ['D', 'E']])
assert rst_table.count('==') == 9
assert 'A B -' in rst_table
assert 'D E -' in rst_table
# check total rows
field = fields.TableRowsField(id='1', label='Foobar', columns=['aa', 'ab', 'ac'], total_row=True)
html_table = str(field.get_view_value([['A', 'B', '10'], ['D', 'E', '20']]))
assert html_table.count('<tr>') == 4
assert html_table.count('<th>') == 3
assert html_table.count('<td>') == 9
assert html_table.count('<tfoot>') == 1
assert '<td>30.00</td>' in html_table
def test_date():
assert fields.DateField().convert_value_from_str('2015-01-04') is not None
assert fields.DateField().convert_value_from_str('04/01/2015') is not None
assert fields.DateField().convert_value_from_str('') is None
assert fields.DateField().convert_value_from_str('not a date') is None
def test_date_anonymise(pub):
formdef = FormDef()
formdef.name = 'title'
formdef.fields = [fields.DateField(id='0', label='date', type='date')]
formdef.store()
formdata = formdef.data_class()()
formdata.just_created()
formdata.data = {'0': time.strptime('2023-03-28', '%Y-%m-%d')}
formdata.anonymise()
assert not formdata.data.get('0')
formdef.fields[0].anonymise = False
formdef.store()
formdata = formdef.data_class()()
formdata.just_created()
formdata.data = {'0': time.strptime('2023-03-28', '%Y-%m-%d')}
formdata.anonymise()
assert formdata.data.get('0') == time.strptime('2023-03-28', '%Y-%m-%d')
def test_file_convert_from_anything():
assert fields.FileField().convert_value_from_anything(None) is None
value = fields.FileField().convert_value_from_anything({'content': 'hello', 'filename': 'test.txt'})
assert value.base_filename == 'test.txt'
assert value.get_file_pointer().read() == b'hello'
value = fields.FileField().convert_value_from_anything(
{'b64_content': 'aGVsbG8=', 'filename': 'test.txt'}
)
assert value.base_filename == 'test.txt'
assert value.get_file_pointer().read() == b'hello'
formdef = FormDef()
formdef.name = 'foobarlazy'
formdef.fields = [fields.FileField(id='5', label='file', varname='filefield')]
formdef.store()
formdef.data_class().wipe()
formdata = formdef.data_class()()
formdata.data = {
'5': PicklableUpload('test.txt', 'text/plain'),
}
formdata.data['5'].receive([b'hello'])
formdata.store()
value = fields.FileField().convert_value_from_anything(formdef.data_class().get(formdata.id).data['5'])
assert value.base_filename == 'test.txt'
assert value.get_file_pointer().read() == b'hello'
value = fields.FileField().convert_value_from_anything(
LazyFormData(formdef.data_class().get(formdata.id)).var.filefield
)
assert value.base_filename == 'test.txt'
assert value.get_file_pointer().read() == b'hello'
def test_new_field_type_options(pub):
pub.load_site_options()
if not pub.site_options.has_section('options'):
pub.site_options.add_section('options')
pub.site_options.set('options', 'disabled-fields', '')
with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
pub.site_options.write(fd)
assert fields.get_field_options(blacklisted_types=[]) == [
('string', 'Text (line)', 'string'),
('text', 'Long Text', 'text'),
('email', 'Email', 'email'),
('bool', 'Check Box (single choice)', 'bool'),
('file', 'File Upload', 'file'),
('date', 'Date', 'date'),
('item', 'List', 'item'),
('items', 'Multiple choice list', 'items'),
('table', 'Table', 'table'),
('table-select', 'Table of Lists', 'table-select'),
('tablerows', 'Table with rows', 'tablerows'),
('map', 'Map', 'map'),
('ranked-items', 'Ranked Items', 'ranked-items'),
('password', 'Password', 'password'),
('', '', ''),
('title', 'Title', 'title'),
('subtitle', 'Subtitle', 'subtitle'),
('comment', 'Comment', 'comment'),
('page', 'Page', 'page'),
('', '', ''),
('computed', 'Computed Data', 'computed'),
]
assert fields.get_field_options(blacklisted_types=['password', 'page']) == [
('string', 'Text (line)', 'string'),
('text', 'Long Text', 'text'),
('email', 'Email', 'email'),
('bool', 'Check Box (single choice)', 'bool'),
('file', 'File Upload', 'file'),
('date', 'Date', 'date'),
('item', 'List', 'item'),
('items', 'Multiple choice list', 'items'),
('table', 'Table', 'table'),
('table-select', 'Table of Lists', 'table-select'),
('tablerows', 'Table with rows', 'tablerows'),
('map', 'Map', 'map'),
('ranked-items', 'Ranked Items', 'ranked-items'),
('', '', ''),
('title', 'Title', 'title'),
('subtitle', 'Subtitle', 'subtitle'),
('comment', 'Comment', 'comment'),
('', '', ''),
('computed', 'Computed Data', 'computed'),
]
pub.site_options.set('options', 'disabled-fields', 'table, password, ')
with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
pub.site_options.write(fd)
assert fields.get_field_options(blacklisted_types=[]) == [
('string', 'Text (line)', 'string'),
('text', 'Long Text', 'text'),
('email', 'Email', 'email'),
('bool', 'Check Box (single choice)', 'bool'),
('file', 'File Upload', 'file'),
('date', 'Date', 'date'),
('item', 'List', 'item'),
('items', 'Multiple choice list', 'items'),
('table-select', 'Table of Lists', 'table-select'),
('tablerows', 'Table with rows', 'tablerows'),
('map', 'Map', 'map'),
('ranked-items', 'Ranked Items', 'ranked-items'),
('', '', ''),
('title', 'Title', 'title'),
('subtitle', 'Subtitle', 'subtitle'),
('comment', 'Comment', 'comment'),
('page', 'Page', 'page'),
('', '', ''),
('computed', 'Computed Data', 'computed'),
]
assert fields.get_field_options(blacklisted_types=['password', 'page']) == [
('string', 'Text (line)', 'string'),
('text', 'Long Text', 'text'),
('email', 'Email', 'email'),
('bool', 'Check Box (single choice)', 'bool'),
('file', 'File Upload', 'file'),
('date', 'Date', 'date'),
('item', 'List', 'item'),
('items', 'Multiple choice list', 'items'),
('table-select', 'Table of Lists', 'table-select'),
('tablerows', 'Table with rows', 'tablerows'),
('map', 'Map', 'map'),
('ranked-items', 'Ranked Items', 'ranked-items'),
('', '', ''),
('title', 'Title', 'title'),
('subtitle', 'Subtitle', 'subtitle'),
('comment', 'Comment', 'comment'),
('', '', ''),
('computed', 'Computed Data', 'computed'),
]
def test_block_do_not_pickle_cache(pub):
FormDef.wipe()
BlockDef.wipe()
block = BlockDef()
block.name = 'foobar'
block.fields = [
fields.StringField(id='123', required=True, label='Test', type='string'),
fields.StringField(id='234', required=True, label='Test2', type='string'),
]
block.store()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = [
fields.BlockField(id='1', label='test', type='block:foobar', hint='hintblock'),
]
formdef.store()
assert formdef.fields[0]._block is None
assert formdef.fields[0].block is not None # will cache the value
assert formdef.fields[0]._block is not None
formdef.store()
formdef = FormDef.get(formdef.id)
assert formdef.fields[0]._block is None