Skip to content

Commit

Permalink
Refactor builder component path properties, to store objects, with ke…
Browse files Browse the repository at this point in the history
…y and label getters.
  • Loading branch information
bobslee committed Jul 20, 2023
1 parent 33a22ba commit 53063af
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 36 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
# Changelog

## 1.0.2

Refactor builder component path properties, to store objects, with key and label getters.

## 1.0.1

Fix error in `get_component_object` (`builder.py`) => `NameError: name 'logging is not defined'`\
Accidentally removed the `import logging` in previous version 1.0.0

## 1.0.0

Implement component (object) path properties in a builder (object) context.
Implement builder component path properties (keys, labels).

`builder_path_key`
List of complete path components with keys. This includes layout components.
Expand Down
4 changes: 4 additions & 0 deletions formiodata/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ def __init__(self, schema_json, **kwargs):
@param schema_json
@param lang
"""

if isinstance(schema_json, dict):
self.schema = schema_json
else:
Expand All @@ -29,6 +30,9 @@ def __init__(self, schema_json, **kwargs):
self.i18n = kwargs.get('i18n', {})
self.resources = kwargs.get('resources', {})

# options from kwargs
self.load_path_objects = kwargs.get('load_path_objects', True)

# Raw components from the schema
self._raw_components = []

Expand Down
70 changes: 36 additions & 34 deletions formiodata/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,11 @@ def __init__(self, raw, builder, **kwargs):
# components can also be seen as children
self.components = OrderedDict()

# List of complete path components with keys. This includes
# layout components.
self.builder_path_key = []
# List of complete path components with labels. This includes
# layout components.
self.builder_path_label = []
# List of input components in path with keys. This only
# List of complete path components. This includes layout
# components.
self.builder_path = []
# includes input components, so no layout components.
self.builder_input_path_key = []
# List of input components in path with labels. This only
# includes input components, so no layout components.
self.builder_input_path_label = []
self.builder_input_path = []

# XXX uuid to ensure (hope this won't break anything)
self.id = self.raw.get('id', str(uuid.uuid4()))
Expand Down Expand Up @@ -72,8 +65,9 @@ def load(self, component_owner, parent=None, data=None, all_data=None):
self.builder.component_ids[self.id] = self

# parh
self.set_builder_path()
builder_path_key = '.'.join(self.builder_path_key)
self.set_builder_paths()
builder_path_keys = [p.key for p in self.builder_path]
builder_path_key = '.'.join(builder_path_keys)
self.builder.components_path_key[builder_path_key] = self

def load_data(self, data):
Expand Down Expand Up @@ -143,38 +137,46 @@ def child_component_owner(self):
"""The owner object for child components, to use in the recursion"""
return self.component_owner

def set_builder_path(self):
builder_path_key = [self.key]
builder_path_label = [self.label]
builder_input_path_key = []
builder_input_path_label = []
@property
def builder_path_key(self):
return [p.key for p in self.builder_path]

if self.is_form_component:
builder_input_path_key.append(self.key)
builder_input_path_label.append(self.label)
@property
def builder_path_label(self):
return [p.label for p in self.builder_path]

@property
def builder_input_path_key(self):
return [p.key for p in self.builder_input_path]

@property
def builder_input_path_label(self):
return [p.label for p in self.builder_input_path]

def set_builder_paths(self):
builder_path = [self]
builder_input_path = []
if self.is_form_component:
if self.builder.load_path_objects:
builder_input_path.append(self)
parent = self.parent
while parent:
if hasattr(parent, 'key'):
builder_path_key.append(parent.key)
builder_path_label.append(parent.label)
if self.builder.load_path_objects:
builder_path.append(parent)
if parent.is_form_component:
builder_input_path_key.append(parent.key)
builder_input_path_label.append(parent.label)
if self.builder.load_path_objects:
builder_input_path.append(parent)
parent = parent.parent
elif parent.__class__.__name__ == 'gridRow':
parent = parent.grid
else:
parent = parent.component_owner
builder_path_key.reverse()
builder_path_label.reverse()
self.builder_path_key = builder_path_key
self.builder_path_label = builder_path_label
builder_path.reverse()
self.builder_path = builder_path
# input path
builder_input_path_key.reverse()
builder_input_path_label.reverse()
self.builder_input_path_key = builder_input_path_key
self.builder_input_path_label = builder_input_path_label
builder_input_path.reverse()
self.builder_input_path = builder_input_path

@property
def validate(self):
Expand Down Expand Up @@ -972,7 +974,7 @@ class gridRow:
def __init__(self, grid, data):
self.grid = grid
self.builder = grid.builder
self.builder_path_key = None
self.builder_path = None
self.input_components = {}
self.components = OrderedDict()
self.form = grid.form
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.0.1"
version = "1.0.2"
homepage = "https://github.com/novacode-nl/python-formio-data"
description = "formio.js JSON-data API"
readme = "README.md"
Expand Down
75 changes: 75 additions & 0 deletions tests/test_performance_nested_components.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Copyright Nova Code (http://www.novacode.nl)
# See LICENSE file for full licensing details.

import logging
import time
import unittest

from datetime import datetime, date, timezone, timedelta

from tests.utils import readfile
from formiodata.builder import Builder
from formiodata.form import Form
from formiodata.components import (
columnsComponent,
datetimeComponent,
emailComponent,
numberComponent,
selectComponent,
textfieldComponent,
checkboxComponent,
panelComponent,
datagridComponent,
editgridComponent,
)


class PerformanceNestedTestCase(unittest.TestCase):
logger = logging.getLogger(__name__)
logging.basicConfig(format='\n%(message)s', level=logging.INFO)

def setUp(self):
super(PerformanceNestedTestCase, self).setUp()
self.builder_json = readfile('data', 'test_nested_components_builder.json')
self.form_json = readfile('data', 'test_nested_components_form.json')

def load_builders_range(self, range_num, load_path_objects):
start = time.time()
builders = {}
for n in range(range_num):
builders[n] = Builder(self.builder_json, load_path_objects=load_path_objects)
end = time.time()
msg_lines = [
'----------------------------------------',
'Load Builders range: %s' % range_num,
'Duration: %s' % str(end - start),
'----------------------------------------'
]
self.logger.info('\n'.join(msg_lines))
# self.logger.info(end - start)

def test_Builder_component_with_path_objects(self):
""" Builder: component path objects """

msg_lines = [
'========================================',
'Load Builder WITH path objects',
'========================================',
]
self.logger.info('\n'.join(msg_lines))
self.load_builders_range(10, load_path_objects=True)
self.load_builders_range(100, load_path_objects=True)
self.load_builders_range(1000, load_path_objects=True)

def test_Builder_component_no_path_objects(self):
""" Builder: component NO path objects """

msg_lines = [
'========================================',
'Load Builder NO path objects',
'========================================',
]
self.logger.info('\n'.join(msg_lines))
self.load_builders_range(10, load_path_objects=False)
self.load_builders_range(100, load_path_objects=False)
self.load_builders_range(1000, load_path_objects=False)

0 comments on commit 53063af

Please sign in to comment.