Skip to content

refactor(workflow): add Jinja2 renderer abstraction for template transform#128

Open
tomerqodo wants to merge 6 commits into
qodo_combined_20260121_qodo_grep_cursor_copilot_1_base_refactorworkflow_add_jinja2_renderer_abstraction_for_template_transform_pr433from
qodo_combined_20260121_qodo_grep_cursor_copilot_1_head_refactorworkflow_add_jinja2_renderer_abstraction_for_template_transform_pr433
Open

refactor(workflow): add Jinja2 renderer abstraction for template transform#128
tomerqodo wants to merge 6 commits into
qodo_combined_20260121_qodo_grep_cursor_copilot_1_base_refactorworkflow_add_jinja2_renderer_abstraction_for_template_transform_pr433from
qodo_combined_20260121_qodo_grep_cursor_copilot_1_head_refactorworkflow_add_jinja2_renderer_abstraction_for_template_transform_pr433

Conversation

@tomerqodo

Copy link
Copy Markdown

Benchmark PR from qodo-benchmark#433

laipz8200 and others added 6 commits January 21, 2026 15:54
…de and threaded it through DifyNodeFactory so TemplateTransform nodes receive the dependency by default, keeping behavior unchanged unless an override is provided. Changes are in `api/core/workflow/nodes/template_transform/template_transform_node.py` and `api/core/workflow/nodes/node_factory.py`.

**Commits**
- chore(workflow): identify TemplateTransform dependency on CodeExecutor
- feat(workflow): add CodeExecutor constructor injection to TemplateTransformNode (defaulting to current behavior)
- feat(workflow): inject CodeExecutor from DifyNodeFactory when creating TemplateTransform nodes

**Tests**
- Not run (not requested)

Next step: run `make lint` and `make type-check` if you want to validate the backend checks.
…Transform to use it, keeping CodeExecutor as the default adapter while preserving current behavior. Updates are in `api/core/workflow/nodes/template_transform/template_renderer.py`, `api/core/workflow/nodes/template_transform/template_transform_node.py`, `api/core/workflow/nodes/node_factory.py`, and `api/tests/unit_tests/core/workflow/nodes/template_transform/template_transform_node_spec.py`.

Commit-style summary:
- feat(template-transform): add Jinja2 template renderer abstraction with CodeExecutor adapter
- refactor(template-transform): use renderer in node/factory and update unit test patches

Tests not run (not requested).
…ode creation to return TemplateTransformNode directly for template-transform nodes in `api/core/workflow/nodes/node_factory.py`.

Commit-style summary:
- refactor(template-transform): derive TemplateRenderError from ValueError
- refactor(node-factory): instantiate TemplateTransformNode directly with injected renderer

Tests not run (not requested).
…ts/core/workflow/nodes/template_transform/template_transform_node_spec.py`)

chore(type-check): ran `make type-check` (basedpyright clean, 0 errors)

No errors reported.
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (3) 📎 Requirement gaps (0)

Grey Divider


Action required

1. render_template() may return None 📘 Rule violation ⛯ Reliability
Description
CodeExecutorJinja2TemplateRenderer.render_template() is annotated to return str but can return
  None when result.get("result") is missing/None.
• TemplateTransformNode._run() then calls len(rendered), which will raise a TypeError and
  bypass the intended NodeRunResult failure path.
• This creates an unhandled edge case and breaks graceful degradation for template rendering
  failures.
Code

api/core/workflow/nodes/template_transform/template_renderer.py[R37-40]

+        rendered = result.get("result")
+        if rendered is not None and not isinstance(rendered, str):
+            raise TemplateRenderError("Template render result must be a string.")
+        return rendered
Evidence
The renderer returns rendered even when it is None, despite a str return annotation. The node
then assumes the value is always a string and calls len(rendered), which will crash if None is
returned, indicating missing edge case handling.

Rule 3: Generic: Robust Error Handling and Edge Case Management
api/core/workflow/nodes/template_transform/template_renderer.py[37-40]
api/core/workflow/nodes/template_transform/template_transform_node.py[68-70]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`CodeExecutorJinja2TemplateRenderer.render_template()` can return `None` even though it is annotated as returning `str`. This leads to a `TypeError` in `TemplateTransformNode._run()` when calling `len(rendered)`.

## Issue Context
`result.get(&quot;result&quot;)` may be missing or `None`. The node assumes a string and does not guard against `None`.

## Fix Focus Areas
- api/core/workflow/nodes/template_transform/template_renderer.py[29-40]
- api/core/workflow/nodes/template_transform/template_transform_node.py[67-76]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Test file exceeds 800 📘 Rule violation ⛯ Reliability
Description
api/tests/unit_tests/core/workflow/nodes/template_transform/template_transform_node_spec.py now
  extends well beyond 800 lines (e.g., content exists at line 1151).
• This violates the repository constraint to keep Python files under api/ below 800 lines to
  maintain readability and modularity.
• The test suite should be split or consolidated (e.g., parameterization) to reduce file size.
Code

api/tests/unit_tests/core/workflow/nodes/template_transform/template_transform_node_spec.py[R793-802]

+    @patch(
+        "core.workflow.nodes.template_transform.template_transform_node.CodeExecutorJinja2TemplateRenderer.render_template"
+    )
+    def test_run_with_special_characters(self, mock_execute, mock_graph, mock_graph_runtime_state, graph_init_params):
+        """Test _run with special characters in variables."""
+        node_data = {
+            "title": "Special Chars Template",
+            "variables": [{"variable": "text", "value_selector": ["sys", "input_text"]}],
+            "template": "{{ text }}",
+        }
Evidence
The compliance rule sets a hard file-size limit for Python files under api/. The modified test
file contains executable code at line numbers > 800 (and even > 1100), proving it exceeds the
800-line threshold.

AGENTS.md
api/tests/unit_tests/core/workflow/nodes/template_transform/template_transform_node_spec.py[793-802]
api/tests/unit_tests/core/workflow/nodes/template_transform/template_transform_node_spec.py[1150-1151]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A Python test file under `api/` exceeds the 800-line limit.

## Issue Context
The test file contains many repetitive test cases that can likely be consolidated via parameterization or moved into multiple smaller spec modules.

## Fix Focus Areas
- api/tests/unit_tests/core/workflow/nodes/template_transform/template_transform_node_spec.py[430-1151]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. TemplateRenderError leaks internals 📘 Rule violation ⛨ Security
Description
• The code converts CodeExecutionError into TemplateRenderError(str(exc)), which can propagate
  internal implementation details.
• TemplateTransformNode._run() returns error=str(e) in NodeRunResult, which may become
  user-visible depending on how node failures are surfaced.
• This risks exposing sensitive/internal debugging information through error messages instead of
  keeping details in internal logs.
Code

api/core/workflow/nodes/template_transform/template_renderer.py[R34-36]

+        except CodeExecutionError as exc:
+            raise TemplateRenderError(str(exc)) from exc
+
Evidence
The renderer wraps the underlying exception by stringifying it, and the node returns that string as
the node error message. If node errors are exposed to end-users, this violates the requirement to
keep detailed internal error information out of user-facing errors.

Rule 4: Generic: Secure Error Handling
api/core/workflow/nodes/template_transform/template_renderer.py[34-36]
api/core/workflow/nodes/template_transform/template_transform_node.py[75-76]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`TemplateRenderError(str(exc))` may leak internal error details (from `CodeExecutionError`) and is returned as `NodeRunResult.error`.

## Issue Context
The compliance requirement is to keep user-facing errors generic, while retaining detailed context only in internal logs.

## Fix Focus Areas
- api/core/workflow/nodes/template_transform/template_renderer.py[30-36]
- api/core/workflow/nodes/template_transform/template_transform_node.py[75-76]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



ⓘ The new review experience is currently in Beta. Learn more

Qodo Logo

Comment on lines +37 to +40
rendered = result.get("result")
if rendered is not None and not isinstance(rendered, str):
raise TemplateRenderError("Template render result must be a string.")
return rendered

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. render_template() may return none 📘 Rule violation ⛯ Reliability

CodeExecutorJinja2TemplateRenderer.render_template() is annotated to return str but can return
  None when result.get("result") is missing/None.
• TemplateTransformNode._run() then calls len(rendered), which will raise a TypeError and
  bypass the intended NodeRunResult failure path.
• This creates an unhandled edge case and breaks graceful degradation for template rendering
  failures.
Agent prompt
## Issue description
`CodeExecutorJinja2TemplateRenderer.render_template()` can return `None` even though it is annotated as returning `str`. This leads to a `TypeError` in `TemplateTransformNode._run()` when calling `len(rendered)`.

## Issue Context
`result.get("result")` may be missing or `None`. The node assumes a string and does not guard against `None`.

## Fix Focus Areas
- api/core/workflow/nodes/template_transform/template_renderer.py[29-40]
- api/core/workflow/nodes/template_transform/template_transform_node.py[67-76]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +34 to +36
except CodeExecutionError as exc:
raise TemplateRenderError(str(exc)) from exc

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

2. templaterendererror leaks internals 📘 Rule violation ⛨ Security

• The code converts CodeExecutionError into TemplateRenderError(str(exc)), which can propagate
  internal implementation details.
• TemplateTransformNode._run() returns error=str(e) in NodeRunResult, which may become
  user-visible depending on how node failures are surfaced.
• This risks exposing sensitive/internal debugging information through error messages instead of
  keeping details in internal logs.
Agent prompt
## Issue description
`TemplateRenderError(str(exc))` may leak internal error details (from `CodeExecutionError`) and is returned as `NodeRunResult.error`.

## Issue Context
The compliance requirement is to keep user-facing errors generic, while retaining detailed context only in internal logs.

## Fix Focus Areas
- api/core/workflow/nodes/template_transform/template_renderer.py[30-36]
- api/core/workflow/nodes/template_transform/template_transform_node.py[75-76]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +793 to +802
@patch(
"core.workflow.nodes.template_transform.template_transform_node.CodeExecutorJinja2TemplateRenderer.render_template"
)
def test_run_with_special_characters(self, mock_execute, mock_graph, mock_graph_runtime_state, graph_init_params):
"""Test _run with special characters in variables."""
node_data = {
"title": "Special Chars Template",
"variables": [{"variable": "text", "value_selector": ["sys", "input_text"]}],
"template": "{{ text }}",
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

3. Test file exceeds 800 📘 Rule violation ⛯ Reliability

api/tests/unit_tests/core/workflow/nodes/template_transform/template_transform_node_spec.py now
  extends well beyond 800 lines (e.g., content exists at line 1151).
• This violates the repository constraint to keep Python files under api/ below 800 lines to
  maintain readability and modularity.
• The test suite should be split or consolidated (e.g., parameterization) to reduce file size.
Agent prompt
## Issue description
A Python test file under `api/` exceeds the 800-line limit.

## Issue Context
The test file contains many repetitive test cases that can likely be consolidated via parameterization or moved into multiple smaller spec modules.

## Fix Focus Areas
- api/tests/unit_tests/core/workflow/nodes/template_transform/template_transform_node_spec.py[430-1151]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants