Skip to main content

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

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

MIT

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

Metadata

Release files for formio-data 2.1.7

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for formio-data 2.1.7
File Size Uploaded Provenance
formio_data-2.1.7.tar.gz 18.4 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for formio-data 2.1.7
File Interpreter ABI Platform
formio_data-2.1.7-py3-none-any.whl Python 3 none any Details

Total release size: 48.5 kB

Release files / formio_data-2.1.7.tar.gz

Download URL formio_data-2.1.7.tar.gz
Size 18.4 kB
Tags Source
SHA-256 checksum
How to use checksums
25990f996113d18a3a844d1e98a9a7c2ddb5a8f573160741784420460e196b60
BLAKE2b-256 checksum
How to use checksums
54c314b19ee0f8d5798a882aa2126dbf8841765922f7a045c4b1f104c9dcef21
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.1.3 CPython/3.12.11 Darwin/24.6.0

Release files / formio_data-2.1.7-py3-none-any.whl

Download URL formio_data-2.1.7-py3-none-any.whl
Size 30.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
cb75397d565c83d77bdada8c47a2e3111dc888a582ca092317096876cc3a75a1
BLAKE2b-256 checksum
How to use checksums
d9d538dbcb35b1429b0da16124a3d9066341e5b940eaf29a00c8f011312e2f9a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.1.3 CPython/3.12.11 Darwin/24.6.0

Security for formio-data 2.1.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

2.1.7 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page