Skip to content

Commit 567e421

Browse files
docs(formatter): document True/None deferral and add None regression tests
- Expand normalize_functions docstrings in FormatConfig and format_model_expressions to explicitly document True and None as aliases that defer to SQLGlot's default (uppercase custom functions), contrasting them with False (preserve) and the string modes. - Add None regression assertions to the existing normalize_functions test: one for the multi-expression path and one for the single-meta-expression path, both proving that lowercase audit names are uppercased when normalize_functions=None is passed explicitly. - Update docs/reference/configuration.md to mention 'true' alongside 'null' as a valid value that defers to the SQLGlot default. mypy skipped: errors are pre-existing in unrelated files (cache.py, macros.py, state_sync/base.py) and were present before this branch. Signed-off-by: Alberto Suman <alberto.suman@1komma5grad.com> Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 4e69e81 commit 567e421

4 files changed

Lines changed: 63 additions & 6 deletions

File tree

docs/reference/configuration.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ Formatting settings for the `sqlmesh format` command and UI.
114114
| `normalize` | Whether to normalize SQL (Default: False) | boolean | N |
115115
| `pad` | The number of spaces to use for padding (Default: 2) | int | N |
116116
| `indent` | The number of spaces to use for indentation (Default: 2) | int | N |
117-
| `normalize_functions` | How to normalize function name casing. `False` (default) preserves the casing of custom and audit function names as written; `"upper"` uppercases all function names; `"lower"` lowercases all function names; `null` defers to SQLGlot's generator default, which uppercases all function names including custom ones. Note: SQLGlot built-in function names may still be canonicalized by the parser regardless of this setting. | string \| boolean \| null | N |
117+
| `normalize_functions` | How to normalize function name casing. `False` (default) preserves the casing of custom and audit function names as written; `"upper"` uppercases all function names; `"lower"` lowercases all function names; `true` or `null` defers to SQLGlot's generator default, which uppercases all function names including custom ones. Note: SQLGlot built-in function names may still be canonicalized by the parser regardless of this setting. | string \| boolean \| null | N |
118118
| `leading_comma` | Whether to use leading commas (Default: False) | boolean | N |
119119
| `max_text_width` | The maximum text width in a segment before creating new lines (Default: 80) | int | N |
120120
| `append_newline` | Whether to append a newline to the end of the file (Default: False) | boolean | N |

sqlmesh/core/config/format.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,18 @@ class FormatConfig(BaseConfig):
1212
normalize: Whether to normalize the SQL code or not.
1313
pad: The number of spaces to use for padding.
1414
indent: The number of spaces to use for indentation.
15-
normalize_functions: How to normalize function name casing. Use ``False`` (default) to
16-
preserve the original casing, ``"upper"`` to uppercase all function names, or
17-
``"lower"`` to lowercase all function names.
15+
normalize_functions: How to normalize function name casing.
16+
17+
* ``False`` (default) — preserves the original spelling of custom and audit
18+
function names. SQLGlot built-in functions (e.g. ``COUNT``, ``SUM``) may
19+
still be uppercased because the parser discards the original token.
20+
* ``"upper"`` — uppercases all function names, including custom audit
21+
references.
22+
* ``"lower"`` — lowercases all function names, including built-in ones.
23+
* ``True`` or ``None`` — defers to SQLGlot's generator default, which
24+
uppercases all function names including custom ones. These two values are
25+
equivalent; ``None`` passes the deferral explicitly rather than relying on
26+
the SQLGlot default.
1827
leading_comma: Whether to use leading commas or not.
1928
max_text_width: The maximum text width in a segment before creating new lines.
2029
append_newline: Whether to append a newline to the end of the file or not.

sqlmesh/core/dialect.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -799,8 +799,17 @@ def format_model_expressions(
799799
expressions: The model's expressions, must be at least model def + query.
800800
dialect: The dialect to render the expressions as.
801801
rewrite_casts: Whether to rewrite all casts to use the :: syntax.
802-
normalize_functions: How to normalize function name casing. ``False`` (default)
803-
preserves original casing; ``"upper"`` uppercases; ``"lower"`` lowercases.
802+
normalize_functions: How to normalize function name casing.
803+
804+
* ``False`` (default) — preserves the original spelling of custom and audit
805+
function names. SQLGlot built-in functions may still canonicalize because
806+
the parser discards the original token.
807+
* ``"upper"`` — uppercases all function names including custom audit
808+
references.
809+
* ``"lower"`` — lowercases all function names including built-ins.
810+
* ``True`` or ``None`` — defers to SQLGlot's generator default, which
811+
uppercases all function names including custom ones. Passing ``None``
812+
makes the deferral explicit rather than relying on the SQLGlot default.
804813
**kwargs: Additional keyword arguments to pass to the sql generator.
805814
806815
Returns:

tests/core/test_dialect.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,29 @@ def test_format_model_expressions_normalize_functions():
436436
FROM foo"""
437437
)
438438

439+
# None: explicit deferral to SQLGlot default → custom/audit names uppercased,
440+
# just like "upper". This is distinct from False (preserve) and must be tested
441+
# explicitly because None used to be indistinguishable from the missing kwarg.
442+
assert (
443+
format_model_expressions(expressions, normalize_functions=None)
444+
== """MODEL (
445+
name x,
446+
audits (
447+
UNIQUE_COMBINATION_OF_COLUMNS(columns := (
448+
id
449+
)),
450+
NOT_NULL(columns := (
451+
id
452+
))
453+
)
454+
);
455+
456+
SELECT
457+
SUM(id),
458+
COUNT(id)
459+
FROM foo"""
460+
)
461+
439462
# Single-meta-expression path: normalize_functions must be forwarded.
440463
# Without the fix, this path ignored normalize_functions entirely.
441464
single_model = parse(
@@ -480,6 +503,22 @@ def test_format_model_expressions_normalize_functions():
480503
)"""
481504
)
482505

506+
# Single-meta path, None: custom audit names are uppercased (explicit SQLGlot default deferral).
507+
assert (
508+
format_model_expressions(single_model, normalize_functions=None)
509+
== """MODEL (
510+
name x,
511+
audits (
512+
UNIQUE_COMBINATION_OF_COLUMNS(columns := (
513+
id
514+
)),
515+
NOT_NULL(columns := (
516+
id
517+
))
518+
)
519+
)"""
520+
)
521+
483522

484523
def test_format_config_normalize_functions_false():
485524
config = FormatConfig(normalize_functions=False)

0 commit comments

Comments
 (0)