formio.js JSON-data API
Project description
formio-data (Python)
formio.js (JSON Form Builder) data API for Python.
For information about the formio.js project, see https://github.com/formio/formio.js
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
captured as Python objects, which makes this API very versatile and usable.
Notes about terms:
- Builder: The Form Builder which is the design/blueprint of a Form.
- Form: A filled-in Form, aka Form submission.
- Component: Input (field) or layout component in the Form Builder and Form.
Features
- Compatible with Python 3.6 and later
- Constructor of the Builder and Form class, only requires the JSON and an optional language code for translations.
- Get a Form object its Components as a usable object e.g. datetime, boolean, dict (for select component) etc.
- Open source (MIT License)
Installation
The source code is currently hosted on GitHub at: https://github.com/novacode-nl/python-formio-data
PyPI - Python Package Index
Binary installers for the latest released version are available at the Python Package Index
pip(3) install formio-data
Optional dependencies
To support conditional visibility using JSON logic, you can install
the json-logic-qubit
package (the json-logic
package it is forked
off of is currently unmaintained). It's also possible to install it
via the pip feature json_logic
like so:
pip(3) install -U formio-data[json_logic]
Source Install with Poetry (recommended)
Convenient for developers. Also useful for running the (unit)tests.
git clone git@github.com:novacode-nl/python-formio-data.git
poetry install
Optional dependencies
When working in the project itself, use
poetry install -E json_logic
Source Install with pip
Optional dependencies need to be installed separately.
pip(3) install -U -e python-formio-data
Using direnv
You can use nixpkgs to run a self-contained Python environment without any additional setup. Once you've installed nixpkgs, switch into the directory and type "nix-shell" to get a shell from which the correct Python with packages is available.
If you're using direnv, use direnv allow
after changing into the project directory and you're good to go. Also
consider nix-direnv to
speed up the experience (it can re-use a cached local installation).
License
Contributing
All contributions, bug reports, bug fixes, documentation improvements, enhancements and ideas are welcome.
Usage examples
For more examples of usage, see the unit-tests.
>> from formiodata import Builder, Form
>>
# builder_json is a formio.js Builder JSON document (text/string)
# form_json is a formio.js Form JSON document (text/string)
>>
>> builder = Builder(builder_json)
>> form = Form(builder, form_json)
##################
# input components
##################
# textfield label
>> print(form.input_components['firstname'].label)
'First Name'
# textfield value
>> print(form.input_components['firstname'].value)
'Bob'
# datetime label
>> print(form.input_components['birthday'].label)
'Birthday'
# datetime value
>> print(form.input_components['birthday'].value)
'2009-10-16'
>> print(form.input_components['birthday'].to_date())
datetime.date(2009 10 16)
# datagrid (rows property)
>> print(form.input_components['datagridMeasurements'].rows)
[
{'measurementDatetime': <datetimeComponent>, 'measurementFahrenheit': <numberComponent>},
{'measurementDatetime': <datetimeComponent>, 'measurementFahrenheit': <numberComponent>}
]
>> for row in form.input_components['datagridMeasurements'].rows:
>> dtime = row['measurementDatetime']
>> fahrenheit = row['measurementFahrenheit']
>> print(%s: %s, %s: %s' % (dt.label, dt.to_datetime(), fahrenheit.label, fahrenheit.value))
Datetime: datetime.datetime(2021, 5, 8, 11, 39, 0, 296487), Fahrenheit: 122
Datetime: datetime.datetime(2021, 5, 8, 11, 41, 5, 919943), Fahrenheit: 131
# alternative example, by getattr
>> print(form.data.firstname.label)
'First Name'
>> 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)
#############################
# datagrid input
>> datagridMeasurements = builder.components['datagridMeasurements']
# builder_path
>> [
>> print(row.input_components['measurementDatetime'].builder_path)
>> for row in datagridMeasurements.rows
>> ]
[<panelComponent>, <columnsComponent>, <datagridComponent>, <datetimeComponent>]
# builder_path_key
>> [
>> print(row.input_components['measurementDatetime'].builder_path_key)
>> for row in datagridMeasurements.rows
>> ]
['pageMeasurements', 'columnsExternal', 'datagridMeasurements', 'measurementDatetime']
# builder_path_labels
>> [
>> print(row.input_components['measurementDatetime'].builder_path_labels)
>> for row in datagridMeasurements.rows
>> ]
['Page Measurements', 'Columns External', 'Data Grid Measurements', 'Measurement Datetime']
# builder_input_path
>> [
>> print(row.input_components['measurementDatetime'].builder_input_path)
>> for row in datagridMeasurements.rows
>> ]
[<datagridComponent>, <datetimeComponent>]
# builder_input_path_key
>> [
>> print(row.input_components['measurementDatetime'].builder_input_path_key)
>> for row in datagridMeasurements.rows
>> ]
['datagridMeasurements', 'measurementDatetime']
# builder_input_path_labels
>> [
>> print(row.input_components['measurementDatetime'].builder_input_path_labels)
>> for row in datagridMeasurements.rows
>> ]
['Data Grid Measurements', 'Measurement Datetime']
#################################
# components (layout, input etc.)
#################################
# columns
>> print(form.components['addressColumns'])
<columnsComponent>
>> print(form.components['addressColumns'].rows)
[
{'firstName': <textfieldComponent>, 'lastName: <textfieldComponent>},
{'email': <emailComponent>, 'companyName: <textfieldComponent>}
]
##########################
# components class mapping
##########################
# Below an example which verbosely shows the feature:
# - First set a custom component type 'custom_editgrid' in the Builder JSON schema.
# - Check (assert) whether the component object is an instance of the mapped editgridComponent.
# This code is also present in the unittest (file): tests/test_component_class_mapping.py
schema_dict = json.loads(self.builder_json)
# change 'editgrid' type to 'custom_editgrid'
for comp in schema_dict['components']:
if comp['key'] == 'editGrid':
comp['type'] = 'custom_editgrid'
component_class_mapping = {'custom_editgrid': editgridComponent}
builder = Builder(
schema_json,
component_class_mapping=component_class_mapping,
)
custom_editgrid = builder.components['editGrid']
self.assertIsInstance(custom_editgrid, editgridComponent)
self.assertEqual(custom_editgrid.type, 'custom_editgrid')
Unit tests
Note:
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
From toplevel directory:
poetry install -E json_logic # if you haven't already
poetry run python -m unittest
Run component unittests
All Components, from toplevel directory:
poetry run python -m unittest tests/test_component_*.py
Nested components (complexity), from toplevel directory:
poetry run python -m unittest tests/test_nested_components.py
Run specific component unittest
poetry run python -m unittest tests.test_component_day.dayComponentTestCase.test_get_form_dayMonthYear
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file formio-data-2.1.0.tar.gz
.
File metadata
- Download URL: formio-data-2.1.0.tar.gz
- Upload date:
- Size: 20.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.1.5 CPython/3.9.6 Linux/6.6.46
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 0b2f7e40d41d3beb26762f27d58a9ecff7941d81cab467d21c1f835999322fd3 |
|
MD5 | a77d277efd7b89a09b84a3dd746079de |
|
BLAKE2b-256 | e82e30fe9b5289f6ceebd4098a7984d534593f1a93dde3f64e7e4c79dde35581 |
File details
Details for the file formio_data-2.1.0-py3-none-any.whl
.
File metadata
- Download URL: formio_data-2.1.0-py3-none-any.whl
- Upload date:
- Size: 29.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.1.5 CPython/3.9.6 Linux/6.6.46
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 024802d13c7802ccb79fa8bc9c1139eee5c4fb9b8a30fcf1b07f60f5454aa07b |
|
MD5 | 094cb3724cb95241ebe2f57e54885e8b |
|
BLAKE2b-256 | 87f0cfeda2de6f9a498576b96ccb2b42db24308ab1e5f925c31d27da2a42b176 |