diff --git a/CHANGELOG.md b/CHANGELOG.md index 5164921..cdfe929 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## 1.2.4 + +Implementation of "simple" validation required. + +For a Form object the validation errors can be retrieved by the new +`validation_errors()` method. + +The new component method `validation_errors()` can be extended and +returns either a dictionary or a list (for grid components) with the +validation errors. + ## 1.2.3 Improve the `datetimeComponent` to properly parse a date with a custom format, when the `enableTime` (new property) is False. diff --git a/README.md b/README.md index a0408dd..24e7c8c 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,8 @@ For information about the formio.js project, see https://github.com/formio/formi ## Introduction **python-formio-data** is a Python package, which loads and transforms -formio.js **Builder JSON** and **Form JSON** into **usable Python objects**. It's main -aim is to provide easy access to a Form its components/fields, also +formio.js **Builder JSON** and **Form JSON** into **usable Python objects**.\ +It's main aim is to provide easy access to a Form its components/fields, also captured as **Python objects**, which makes this API very versatile and usable. **Notes about terms:** @@ -147,6 +147,21 @@ Datetime: datetime.datetime(2021, 5, 8, 11, 41, 5, 919943), Fahrenheit: 131 >> print(form.data.firstname.value) 'Bob' +################### +# validation errors +################### + +>> print(form.validation_errors()) +{ + 'companyName': 'Company Name is required', + 'editgridActivities': [ + {'description': 'Description is required'}, + {}, # no validation error (row 2) + {}, # no validation error (row 3) + {'description': 'Description is required', 'startDate': 'Start Date is required'} + ] +} + ############################# # component path (properties) ############################# @@ -241,7 +256,7 @@ self.assertEqual(custom_editgrid.type, 'custom_editgrid') **Note:** -Internet access is recommended for running the `filecStorageUrlComponentTestCase`, because this also tests the URL Storage (type).\ +Internet access is recommended for running the `fileStorageUrlComponentTestCase`, because this also tests the URL Storage (type).\ If no internet access, this test won't fail and a WARNING shall be logged regarding a ConnectionError. ### Run all unittests diff --git a/pyproject.toml b/pyproject.toml index 816ac81..2bde3cd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "formio-data" -version = "1.2.3" +version = "1.2.4" homepage = "https://github.com/novacode-nl/python-formio-data" description = "formio.js JSON-data API" readme = "README.md" diff --git a/tests/test_conditional_visibility_json_logic.py b/tests/test_conditional_visibility_json_logic.py index e700c60..b43454d 100644 --- a/tests/test_conditional_visibility_json_logic.py +++ b/tests/test_conditional_visibility_json_logic.py @@ -8,7 +8,6 @@ from formiodata.form import Form - class ConditionalVisibilityJsonLogicTestCase(ConditionalVisibilityTestHelpers, unittest.TestCase): def setUp(self): super(ConditionalVisibilityJsonLogicTestCase, self).setUp() @@ -17,14 +16,14 @@ def setUp(self): self.hide_secret_form_json = readfile('data', 'test_conditional_visibility_json_logic_hide_secret.json') self.show_secret_form_json = readfile('data', 'test_conditional_visibility_json_logic_show_secret.json') - def test_conditionally_shown_form_elements_have_default_state_in_builder(self): + def test_conditionally_shown_components_have_default_state_in_builder(self): builder = Builder(self.builder_json) self.assertVisible(builder.input_components['username']) self.assertVisible(builder.input_components['password']) self.assertNotVisible(builder.input_components['secret']) - def test_conditionally_shown_form_elements_toggle_on_condition_being_met(self): + def test_conditionally_shown_components_toggle_on_condition_being_met(self): builder = Builder(self.builder_json) hide_secret_form = Form(self.hide_secret_form_json, builder) @@ -37,7 +36,7 @@ def test_conditionally_shown_form_elements_toggle_on_condition_being_met(self): self.assertVisible(show_secret_form.input_components['password']) self.assertVisible(show_secret_form.input_components['secret']) - def test_conditionally_shown_form_elements_do_not_render_when_hidden(self): + def test_conditionally_shown_components_do_not_render_when_hidden(self): builder = Builder(self.builder_json) hide_secret_form = Form(self.hide_secret_form_json, builder) diff --git a/tests/test_conditional_visibility_nested_json_logic.py b/tests/test_conditional_visibility_nested_json_logic.py index 6e285fe..c29617d 100644 --- a/tests/test_conditional_visibility_nested_json_logic.py +++ b/tests/test_conditional_visibility_nested_json_logic.py @@ -18,16 +18,14 @@ def setUp(self): self.hide_global_secret_only_form_json = readfile('data', 'test_conditional_visibility_nested_json_logic_hide_global_secret_only.json') self.show_global_secret_only_form_json = readfile('data', 'test_conditional_visibility_nested_json_logic_show_global_secret_only.json') - - def test_conditionally_shown_top_level_form_elements_have_default_state_in_builder(self): + def test_conditionally_shown_top_level_components_have_default_state_in_builder(self): builder = Builder(self.builder_json) self.assertVisible(builder.input_components['username']) self.assertVisible(builder.input_components['password']) self.assertNotVisible(builder.input_components['secret']) - - def test_conditionally_shown_form_elements_in_panel_have_default_state_in_builder(self): + def test_conditionally_shown_components_in_panel_have_default_state_in_builder(self): builder = Builder(self.builder_json) self.assertVisible(builder.input_components['username1']) @@ -38,8 +36,7 @@ def test_conditionally_shown_form_elements_in_panel_have_default_state_in_builde self.assertVisible(builder.input_components['password2']) self.assertNotVisible(builder.input_components['secret2']) - - def test_conditionally_shown_top_level_form_elements_toggle_on_condition_being_met(self): + def test_conditionally_shown_top_level_components_toggle_on_condition_being_met(self): builder = Builder(self.builder_json) hide_secret_form = Form(self.hide_secret_form_json, builder) @@ -52,8 +49,7 @@ def test_conditionally_shown_top_level_form_elements_toggle_on_condition_being_m self.assertVisible(show_secret_form.input_components['password']) self.assertVisible(show_secret_form.input_components['secret']) - - def test_conditionally_shown_form_elements_in_panel_toggle_on_condition_being_met(self): + def test_conditionally_shown_components_in_panel_toggle_on_condition_being_met(self): builder = Builder(self.builder_json) hide_secret_form = Form(self.hide_secret_form_json, builder) @@ -74,8 +70,7 @@ def test_conditionally_shown_form_elements_in_panel_toggle_on_condition_being_me self.assertVisible(show_secret_form.input_components['password2']) self.assertVisible(show_secret_form.input_components['secret2']) - - def test_conditionally_shown_form_elements_in_data_grid_toggle_on_local_row_condition_met(self): + def test_conditionally_shown_components_in_data_grid_toggle_on_local_row_condition_met(self): builder = Builder(self.builder_json) hide_secret_form = Form(self.hide_secret_form_json, builder) @@ -108,8 +103,7 @@ def test_conditionally_shown_form_elements_in_data_grid_toggle_on_local_row_cond self.assertVisible(show_secret_second_row.input_components['secret3']) self.assertVisible(show_secret_second_row.input_components['globalSecret']) - - def test_conditionally_shown_form_elements_in_data_grid_toggle_on_global_data_condition_met(self): + def test_conditionally_shown_components_in_data_grid_toggle_on_global_data_condition_met(self): builder = Builder(self.builder_json) show_global_secret_only_form = Form(self.show_global_secret_only_form_json, builder) @@ -142,8 +136,7 @@ def test_conditionally_shown_form_elements_in_data_grid_toggle_on_global_data_co self.assertVisible(hide_global_secret_only_second_row.input_components['secret3']) self.assertNotVisible(hide_global_secret_only_second_row.input_components['globalSecret']) - - def test_conditionally_shown_top_level_form_elements_do_not_render_when_hidden(self): + def test_conditionally_shown_top_level_components_do_not_render_when_hidden(self): builder = Builder(self.builder_json) hide_secret_form = Form(self.hide_secret_form_json, builder) @@ -158,8 +151,7 @@ def test_conditionally_shown_top_level_form_elements_do_not_render_when_hidden(s self.assertEqual('

secret

', show_secret_form.input_components['password'].html_component) self.assertEqual('

Secret message

', show_secret_form.input_components['secret'].html_component) - - def test_conditionally_shown_form_elements_in_panel_do_not_render_when_hidden(self): + def test_conditionally_shown_components_in_panel_do_not_render_when_hidden(self): builder = Builder(self.builder_json) hide_secret_form = Form(self.hide_secret_form_json, builder) @@ -182,8 +174,7 @@ def test_conditionally_shown_form_elements_in_panel_do_not_render_when_hidden(se self.assertEqual('

secret

', show_secret_form.input_components['password2'].html_component) self.assertEqual('

Secret message

', show_secret_form.input_components['secret2'].html_component) - - def test_conditionally_shown_form_elements_for_local_row_condition_in_data_grid_do_not_render_when_hidden(self): + def test_conditionally_shown_components_for_local_row_condition_in_data_grid_do_not_render_when_hidden(self): builder = Builder(self.builder_json) hide_secret_form = Form(self.hide_secret_form_json, builder) @@ -234,8 +225,7 @@ def test_conditionally_shown_form_elements_for_local_row_condition_in_data_grid_ show_secret_datagrid.html_component ) - - def test_conditionally_shown_form_elements_for_global_data_condition_in_data_grid_do_not_render_when_hidden(self): + def test_conditionally_shown_components_for_global_data_condition_in_data_grid_do_not_render_when_hidden(self): builder = Builder(self.builder_json) show_global_secret_only_form = Form(self.show_global_secret_only_form_json, builder) diff --git a/tests/test_conditional_visibility_simple.py b/tests/test_conditional_visibility_simple.py index 3c747f7..fe34a0d 100644 --- a/tests/test_conditional_visibility_simple.py +++ b/tests/test_conditional_visibility_simple.py @@ -17,7 +17,7 @@ def setUp(self): self.show_selectboxes_form_json = readfile('data', 'test_conditional_visibility_simple_show_selectboxes.json') self.show_textfield_form_json = readfile('data', 'test_conditional_visibility_simple_show_textfield.json') - def test_conditionally_shown_form_elements_have_default_state_in_builder(self): + def test_conditionally_shown_components_have_default_state_in_builder(self): builder = Builder(self.builder_json) self.assertVisible(builder.input_components['textField']) @@ -26,7 +26,7 @@ def test_conditionally_shown_form_elements_have_default_state_in_builder(self): self.assertNotVisible(builder.input_components['sales']) self.assertNotVisible(builder.input_components['technology']) - def test_conditionally_shown_form_elements_toggle_on_condition_being_met(self): + def test_conditionally_shown_components_toggle_on_condition_being_met(self): builder = Builder(self.builder_json) hide_password_form = Form(self.hide_password_form_json, builder) @@ -44,7 +44,7 @@ def test_conditionally_shown_form_elements_toggle_on_condition_being_met(self): self.assertVisible(show_selectboxes_form.input_components['technology']) self.assertNotVisible(show_selectboxes_form.input_components['sales']) - def test_conditionally_shown_form_elements_do_not_render_when_hidden(self): + def test_conditionally_shown_components_do_not_render_when_hidden(self): builder = Builder(self.builder_json) hide_password_form = Form(self.hide_password_form_json, builder)