Skip to content

Conversation

@m1so
Copy link
Member

@m1so m1so commented Nov 11, 2025

Summary by CodeRabbit

  • Bug Fixes
    • Corrected SQL template escaping so percent signs are only escaped for parameter styles that require it; ensured DuckDB uses the qmark parameter style by default and queries with percent signs are executed unchanged.
  • Tests
    • Added tests covering escaping and parameter-style behavior for qmark, pyformat, and format to prevent regressions.

@linear
Copy link

linear bot commented Nov 11, 2025

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 11, 2025

📝 Walkthrough

Walkthrough

The Jinja SQL rendering utilities were changed so render_jinja_sql_template computes an effective_param_style (replacing earlier inline defaulting) and passes it to _escape_jinja_template. _escape_jinja_template signature now accepts param_style: str = "pyformat" and only escapes percent signs when param_style is "format" or "pyformat"; for other styles (e.g., "qmark") it returns the template unchanged. Tests were added to validate escaping for qmark, pyformat, and format. Separately, SQL execution now maps DuckDB to qmark when param-style auto-detection yields None and no longer unescapes/rebuilds percent signs before executing DuckDB queries.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Caller
  participant render_jinja_sql_template
  participant _escape_jinja_template
  participant JinjaSql
  participant render_result

  Caller->>render_jinja_sql_template: call(template, param_style?)
  alt param_style provided
    render_jinja_sql_template->>render_jinja_sql_template: effective_param_style = provided
  else auto-detect or default
    render_jinja_sql_template->>render_jinja_sql_template: determine effective_param_style (new variable)
  end
  render_jinja_sql_template->>_escape_jinja_template: _escape_jinja_template(template, effective_param_style)
  alt effective_param_style == "format" or "pyformat"
    _escape_jinja_template-->>render_jinja_sql_template: return template with percent signs escaped (%%)
  else
    _escape_jinja_template-->>render_jinja_sql_template: return original template
  end
  render_jinja_sql_template->>JinjaSql: construct with effective_param_style
  JinjaSql->>render_result: render SQL + bind_params
  render_result-->>Caller: return (sql, bind_params)
Loading
sequenceDiagram
  autonumber
  participant Caller
  participant SQLExecutor
  participant DuckDBExecutor

  Caller->>SQLExecutor: execute_sql(connection_info, query, param_style=None)
  SQLExecutor->>SQLExecutor: detect param_style from connection if None
  opt dialect == "deepnote+duckdb" or dialect == "duckdb" and param_style is None
    SQLExecutor->>SQLExecutor: set param_style = "qmark" (new mapping/explicit set)
  end
  SQLExecutor->>DuckDBExecutor: execute_duckdb_sql(query, param_style="qmark")
  DuckDBExecutor->>DuckDBExecutor: execute query unchanged (no unescape/rebuild of %)
  DuckDBExecutor-->>SQLExecutor: execution result (or preview dataframe)
  SQLExecutor-->>Caller: return result
Loading

Possibly related PRs

  • deepnote/deepnote-toolkit#213 — Overlaps with percent-sign handling in the DuckDB execution path; touches similar code paths for DuckDB percent escaping.

Suggested reviewers

  • mfranczel

Pre-merge checks

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Title directly addresses the main fix: conditional escaping logic for SQL templates based on parameter style, with specific focus on qmark support.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between ca88d1e and 1217282.

📒 Files selected for processing (1)
  • tests/unit/test_sql_execution.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
tests/unit/test_sql_execution.py (1)
deepnote_toolkit/sql/sql_execution.py (1)
  • execute_sql (198-234)
🪛 Ruff (0.14.4)
tests/unit/test_sql_execution.py

74-74: Use a regular assert instead of unittest-style assertEqual

Replace assertEqual(...) with assert ...

(PT009)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: codecov/patch
  • GitHub Check: Build and push artifacts for Python 3.11
  • GitHub Check: Build and push artifacts for Python 3.13
  • GitHub Check: Build and push artifacts for Python 3.10
  • GitHub Check: Build and push artifacts for Python 3.12
  • GitHub Check: Build and push artifacts for Python 3.9
  • GitHub Check: Test - Python 3.11
  • GitHub Check: Test - Python 3.13
  • GitHub Check: Test - Python 3.9
  • GitHub Check: Test - Python 3.10
🔇 Additional comments (1)
tests/unit/test_sql_execution.py (1)

63-74: LGTM! Test correctly validates qmark defaulting behavior.

The test appropriately verifies that when param_style is null for DuckDB, it defaults to "qmark" and doesn't escape percent signs. The logic directly validates the PR's objective.

Minor: Line 74 could use assert instead of self.assertEqual for consistency with line 73, but this mixed style already exists throughout the file.


Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

github-actions bot commented Nov 11, 2025

📦 Python package built successfully!

  • Version: 1.1.2.dev7+2a8120d
  • Wheel: deepnote_toolkit-1.1.2.dev7+2a8120d-py3-none-any.whl
  • Install:
    pip install "deepnote-toolkit @ https://deepnote-staging-runtime-artifactory.s3.amazonaws.com/deepnote-toolkit-packages/1.1.2.dev7%2B2a8120d/deepnote_toolkit-1.1.2.dev7%2B2a8120d-py3-none-any.whl"

@codecov
Copy link

codecov bot commented Nov 11, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 75.40%. Comparing base (cc6a555) to head (1217282).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##             main      #27   +/-   ##
=======================================
  Coverage   75.39%   75.40%           
=======================================
  Files          99       99           
  Lines        5625     5627    +2     
  Branches      784      785    +1     
=======================================
+ Hits         4241     4243    +2     
  Misses       1384     1384           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between cc6a555 and 74ae4ec.

📒 Files selected for processing (2)
  • deepnote_toolkit/sql/jinjasql_utils.py (2 hunks)
  • tests/unit/test_jinjasql_utils.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
tests/unit/test_jinjasql_utils.py (1)
deepnote_toolkit/sql/jinjasql_utils.py (1)
  • render_jinja_sql_template (9-36)
🪛 Ruff (0.14.4)
tests/unit/test_jinjasql_utils.py

97-97: Use a regular assert instead of unittest-style assertEqual

Replace assertEqual(...) with assert ...

(PT009)


98-98: Use a regular assert instead of unittest-style assertEqual

Replace assertEqual(...) with assert ...

(PT009)


106-106: Use a regular assert instead of unittest-style assertEqual

Replace assertEqual(...) with assert ...

(PT009)


107-107: Use a regular assert instead of unittest-style assertEqual

Replace assertEqual(...) with assert ...

(PT009)


115-115: Use a regular assert instead of unittest-style assertEqual

Replace assertEqual(...) with assert ...

(PT009)


116-116: Use a regular assert instead of unittest-style assertEqual

Replace assertEqual(...) with assert ...

(PT009)

deepnote_toolkit/sql/jinjasql_utils.py

43-43: Missing return type annotation for private function _escape_jinja_template

(ANN202)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
  • GitHub Check: Test - Python 3.13
  • GitHub Check: Test - Python 3.10
  • GitHub Check: Test - Python 3.11
  • GitHub Check: Test - Python 3.12
  • GitHub Check: Test - Python 3.9
  • GitHub Check: Typecheck - 3.13
  • GitHub Check: Typecheck - 3.9
  • GitHub Check: Build and push artifacts for Python 3.9
  • GitHub Check: Build and push artifacts for Python 3.11
  • GitHub Check: Build and push artifacts for Python 3.12
  • GitHub Check: Build and push artifacts for Python 3.13
  • GitHub Check: Build and push artifacts for Python 3.10
🔇 Additional comments (5)
deepnote_toolkit/sql/jinjasql_utils.py (2)

25-29: Consistent param_style handling looks good.

The effective_param_style variable ensures the same parameter style is used for both escaping and JinjaSql initialization. Clean approach.


43-53: Conditional escaping logic is correct.

Only escaping % for "format" and "pyformat" styles properly addresses the issue with date format strings in qmark style. The regex correctly avoids Jinja blocks.

tests/unit/test_jinjasql_utils.py (3)

92-99: Good test for qmark style.

Validates that date format strings with % are preserved when using qmark parameter style. This directly tests the fix.


100-108: pyformat escaping verified.

Confirms that % is properly escaped for pyformat style (dict-based parameters).


109-117: format escaping verified.

Confirms that % is properly escaped for format style (list-based parameters).

@deepnote-bot
Copy link

deepnote-bot commented Nov 11, 2025

🚀 Review App Deployment Started

📝 Description 🌐 Link / Info
🌍 Review application ra-27
🔑 Sign-in URL Click to sign-in
📊 Application logs View logs
🔄 Actions Click to redeploy
🚀 ArgoCD deployment View deployment
Last deployed 2025-11-11 14:32:03 (UTC)
📜 Deployed commit a72bad371cbf3a241ca342c7e8a63c611b9fea8e
🛠️ Toolkit version 2a8120d

@m1so m1so marked this pull request as ready for review November 11, 2025 14:05
@m1so m1so requested a review from a team as a code owner November 11, 2025 14:05
coderabbitai[bot]
coderabbitai bot previously approved these changes Nov 11, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d75c32f and ca88d1e.

📒 Files selected for processing (1)
  • deepnote_toolkit/sql/sql_execution.py (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: Build and push artifacts for Python 3.13
  • GitHub Check: Build and push artifacts for Python 3.10
  • GitHub Check: Build and push artifacts for Python 3.9
  • GitHub Check: Build and push artifacts for Python 3.11
  • GitHub Check: Build and push artifacts for Python 3.12
  • GitHub Check: Test - Python 3.12
  • GitHub Check: Test - Python 3.13
  • GitHub Check: Test - Python 3.11
  • GitHub Check: Test - Python 3.9
  • GitHub Check: Test - Python 3.10
🔇 Additional comments (1)
deepnote_toolkit/sql/sql_execution.py (1)

298-298: No issues found.

DuckDB's Python API supports qmark-style (?) positional parameters via list/tuple binding, and execute_duckdb_sql correctly passes the list returned by render_jinja_sql_template with qmark style directly to duckdb.execute(parameters=...). The code handles this correctly.

@m1so m1so merged commit 7d91cd6 into main Nov 11, 2025
34 checks passed
@m1so m1so deleted the michalbaumgartner/blu-5147-fix-escaping-in-sql-templating-for-qmark-parameter-style branch November 11, 2025 14:50
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.

4 participants