Skip to content

Commit

Permalink
Merge pull request #36 from bobslee/component-class-mapping
Browse files Browse the repository at this point in the history
Add component_class_mapping feature (argument) for the Builder instantiation
  • Loading branch information
bobslee authored Sep 21, 2023
2 parents b1bead0 + 327d02d commit 0a3c95d
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 16 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Changelog

## 1.2.0

New "component class mapping feature" for the Builder instantiation:\
Map a custom component type to an implemented component class, which is then loaded.

An example is available in the unittests of file: `tests/test_component_class_mapping.py`

Also refactored the Builder constructor, from some `kwargs` to keyword arguments.

## 1.1.0

Put component classes as files in the new `components` directory.\
Expand Down
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,32 @@ Datetime: datetime.datetime(2021, 5, 8, 11, 41, 5, 919943), Fahrenheit: 131
{'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
Expand Down
48 changes: 35 additions & 13 deletions formiodata/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,36 @@

class Builder:

def __init__(self, schema_json, **kwargs):
def __init__(
self,
schema_json,
language='en',
i18n={},
resources={},
load_path_objects=True,
component_class_mapping={},
**kwargs
):
"""
@param schema_json
@param lang
@param language
@param i18n
@param resources
@param resources
@param load_path_objects
@param component_class_mapping
"""

if isinstance(schema_json, dict):
self.schema = schema_json
else:
self.schema = json.loads(schema_json)

self.language = kwargs.get('language', 'en')
# i18n (translations)
self.i18n = kwargs.get('i18n', {})
self.resources = kwargs.get('resources', {})

# options from kwargs
self.load_path_objects = kwargs.get('load_path_objects', True)
self.language = language
self.i18n = i18n
self.resources = resources
self.load_path_objects = load_path_objects
self.component_class_mapping = component_class_mapping

# Raw components from the schema
self._raw_components = []
Expand Down Expand Up @@ -79,10 +91,20 @@ def get_component_object(self, component):
component_type = component.get('type')
if component_type:
try:
cls_name = '%sComponent' % component_type
import_path = 'formiodata.components.%s' % component_type
module = __import__(import_path, fromlist=[cls_name])
cls = getattr(module, cls_name)
try:
mapping_value = self.component_class_mapping[component_type]
if isinstance(mapping_value, str):
cls_name = '%sComponent' % mapping_value
import_path = 'formiodata.components.%s' % mapping_value
module = __import__(import_path, fromlist=[cls_name])
cls = getattr(module, cls_name)
else:
cls = self.component_class_mapping[component_type]
except KeyError:
cls_name = '%sComponent' % component_type
import_path = 'formiodata.components.%s' % component_type
module = __import__(import_path, fromlist=[cls_name])
cls = getattr(module, cls_name)
component_obj = cls(component, self, language=self.language, i18n=self.i18n, resources=self.resources)
return component_obj
except AttributeError as e:
Expand Down
6 changes: 4 additions & 2 deletions formiodata/form.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@

class Form:

def __init__(self, form_json, builder=None, builder_schema_json=None, lang='en', **kwargs):
def __init__(
self, form_json, builder=None, builder_schema_json=None, lang="en", **kwargs
):
"""
@param form_json
@param builder Builder
@param builder_schema
@param builder_schema_json
@param lang
"""
if isinstance(form_json, dict):
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "formio-data"
version = "1.1.0"
version = "1.2.0"
homepage = "https://github.com/novacode-nl/python-formio-data"
description = "formio.js JSON-data API"
readme = "README.md"
Expand Down
41 changes: 41 additions & 0 deletions tests/test_component_class_mapping.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Copyright Nova Code (http://www.novacode.nl)
# See LICENSE file for full licensing details.

import json

from test_common import CommonTestCase
from formiodata.builder import Builder
from formiodata.components.editgrid import editgridComponent


class ComponentClassMappingTestCase(CommonTestCase):

def setUp(self):
super().setUp()

schema_dict = json.loads(self.builder_json)
for comp in schema_dict['components']:
if comp['key'] == 'editGrid':
comp['type'] = 'custom_editgrid'

self.schema_json_component_class_mapping = json.dumps(schema_dict)

def test_component_class_mapping_with_class(self):
component_class_mapping = {'custom_editgrid': editgridComponent}
builder = Builder(
self.schema_json_component_class_mapping,
component_class_mapping=component_class_mapping,
)
custom_editgrid = builder.components['editGrid']
self.assertIsInstance(custom_editgrid, editgridComponent)
self.assertEqual(custom_editgrid.type, 'custom_editgrid')

def test_component_class_mapping_with_string(self):
component_class_mapping = {'custom_editgrid': 'editgrid'}
builder = Builder(
self.schema_json_component_class_mapping,
component_class_mapping=component_class_mapping,
)
custom_editgrid = builder.components['editGrid']
self.assertIsInstance(custom_editgrid, editgridComponent)
self.assertEqual(custom_editgrid.type, 'custom_editgrid')

0 comments on commit 0a3c95d

Please sign in to comment.