Skip to content

Commit

Permalink
fix: generate dynamic default setvalues instead of accumulating to list
Browse files Browse the repository at this point in the history
- avoids creation of an intermediate list per repeat section, and calls
  to list.append() for each node
- avoids iterating through "children" elements that are not part of a
  section, e.g. Options of a Question
  • Loading branch information
lindsay-stevens committed Nov 25, 2024
1 parent 2a4ba80 commit 48b3969
Showing 1 changed file with 10 additions and 12 deletions.
22 changes: 10 additions & 12 deletions pyxform/section.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
Section survey element module.
"""

from collections.abc import Generator
from typing import TYPE_CHECKING

from pyxform.errors import PyXFormError
from pyxform.external_instance import ExternalInstance
from pyxform.survey_element import SurveyElement
from pyxform.utils import node
from pyxform.utils import DetachableElement, node

if TYPE_CHECKING:
from pyxform.survey import Survey
Expand Down Expand Up @@ -121,9 +122,7 @@ def xml_control(self, survey: "Survey"):
for n in Section.xml_control(self, survey=survey):
repeat_node.appendChild(n)

setvalue_nodes = self._get_setvalue_nodes_for_dynamic_defaults(survey=survey)

for setvalue_node in setvalue_nodes:
for setvalue_node in self._dynamic_defaults_helper(current=self, survey=survey):
repeat_node.appendChild(setvalue_node)

label = self.xml_label(survey=survey)
Expand All @@ -132,20 +131,19 @@ def xml_control(self, survey: "Survey"):
return node("group", repeat_node, ref=self.get_xpath(), **self.control)

# Get setvalue nodes for all descendants of this repeat that have dynamic defaults and aren't nested in other repeats.
def _get_setvalue_nodes_for_dynamic_defaults(self, survey: "Survey"):
setvalue_nodes = []
self._dynamic_defaults_helper(current=self, nodes=setvalue_nodes, survey=survey)
return setvalue_nodes

def _dynamic_defaults_helper(self, current: "Section", nodes: list, survey: "Survey"):
def _dynamic_defaults_helper(
self, current: "Section", survey: "Survey"
) -> Generator[DetachableElement, None, None]:
if not isinstance(current, Section):
return
for e in current.children:
if e.type != "repeat": # let nested repeats handle their own defaults
dynamic_default = e.get_setvalue_node_for_dynamic_default(
in_repeat=True, survey=survey
)
if dynamic_default:
nodes.append(dynamic_default)
self._dynamic_defaults_helper(current=e, nodes=nodes, survey=survey)
yield dynamic_default
yield from self._dynamic_defaults_helper(current=e, survey=survey)

# I'm anal about matching function signatures when overriding a function,
# but there's no reason for kwargs to be an argument
Expand Down

0 comments on commit 48b3969

Please sign in to comment.