nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: TobikoData/sqlmesh
Pull request #4233 (2025-04-23 17:15:22)

Fix: address staged file path edge case in snowflake parsing
The behavior today in main is as follows:

```sql
MODEL (
  name test_schema.@{table_name},
  kind FULL,
  blueprints (
    (table_name := "test_table", stage_path := 'foo'),
  )
);

SELECT * FROM @stage_path (file_format => 'bar') LIMIT 100
```

```
(.venv) ➜  sqlmesh render test_schema.test_table
Error: Failed to resolve macros for
SELECT
  *
FROM @stage_path(file_format => 'bar')
LIMIT 100
Macro 'stage_path' does not exist. at '.../playground/models/test_model.sql'
```

This is because the parsing is off:

```python
>>> from sqlmesh.core.dialect import parse_one
>>> parse_one("""
... SELECT
...   *
... FROM @stage_path (FILE_FORMAT => 'foo')
... LIMIT 100
... """, dialect="snowflake")
Select(
  expressions=[
    Star()],
  limit=Limit(
    expression=Literal(this=100, is_string=False)),
  from=From(
    this=Table(
      this=MacroFunc(
        this=Anonymous(
          this=stage_path,
          expressions=[
            Kwarg(
              this=Var(this=FILE_FORMAT),
              expression=Literal(this='foo', is_string=True))])))))
```

Notice the `MacroFunc` here. Instead, we want this to be a `StagedFilePath`, because we can't disambiguate it from Snowflake's stage file syntax.

Alternatively, if I change the variable reference to `@{stage_path}`, then it fails with "Expecting ). Line 9, Col: 43." (`=>` highlighted).


Patch:
diff --git a/sqlmesh/core/dialect.py b/sqlmesh/core/dialect.py
index f3cc64ce..4bd8e865 100644
--- a/sqlmesh/core/dialect.py
+++ b/sqlmesh/core/dialect.py
@@ -500,6 +500,7 @@ def _parse_table_parts(
                 self._curr
                 and self._prev.token_type in (TokenType.L_PAREN, TokenType.R_PAREN)
                 and self._curr.text.upper() not in ("FILE_FORMAT", "PATTERN")
+                and not (table.args.get("format") or table.args.get("pattern"))
             )
         ):
             self._retreat(index)


Test patch:
diff --git a/tests/core/test_model.py b/tests/core/test_model.py
index 89d7e23a..825b39ea 100644
--- a/tests/core/test_model.py
+++ b/tests/core/test_model.py
@@ -7463,6 +7463,23 @@ def test_staged_file_path():
     query = model.render_query()
     assert query.sql(dialect="snowflake") == "SELECT * FROM @a.b/c/d.csv (FILE_FORMAT => 'b.ff')"
 
+    expressions = d.parse(
+        """
+        MODEL (name test, dialect snowflake);
+
+        SELECT
+          *
+        FROM @variable (FILE_FORMAT => 'foo'), @non_variable (FILE_FORMAT => 'bar')
+        LIMIT 100
+        """
+    )
+    model = load_sql_based_model(expressions, variables={"variable": "some_path"})
+    query = model.render_query()
+    assert (
+        query.sql(dialect="snowflake")
+        == """SELECT * FROM 'some_path' (FILE_FORMAT => 'foo') AS "SOME_PATH", @non_variable (FILE_FORMAT => 'bar') LIMIT 100"""
+    )
+
 
 def test_cache():
     expressions = d.parse(
Repository: TobikoData/sqlmesh
Pull request #4259 (2025-04-25 23:40:53)

Fix: address Snowflake table parsing bug
Seems like this one slipped through the cracks.


Patch:
diff --git a/sqlmesh/core/dialect.py b/sqlmesh/core/dialect.py
index bd58f94d..ad5be2e8 100644
--- a/sqlmesh/core/dialect.py
+++ b/sqlmesh/core/dialect.py
@@ -482,9 +482,9 @@ def _parse_table_parts(
     )
 
     table_arg = table.this
-    name = table_arg.name
+    name = table_arg.name if isinstance(table_arg, exp.Var) else ""
 
-    if isinstance(table_arg, exp.Var) and name.startswith(SQLMESH_MACRO_PREFIX):
+    if name.startswith(SQLMESH_MACRO_PREFIX):
         # In these cases, we don't want to produce a `StagedFilePath` node:
         #
         # - @'...' needs to parsed as a string template


Test patch:
diff --git a/tests/core/test_dialect.py b/tests/core/test_dialect.py
index 19b01d70..76a5e66b 100644
--- a/tests/core/test_dialect.py
+++ b/tests/core/test_dialect.py
@@ -699,3 +699,7 @@ def test_model_name_cannot_be_string():
         )
 
     assert "\\'name\\' property cannot be a string value" in str(parse_error)
+
+
+def test_parse_snowflake_create_schema_ddl():
+    assert parse_one("CREATE SCHEMA d.s", dialect="snowflake").sql() == "CREATE SCHEMA d.s"
Repository: TobikoData/sqlmesh
Pull request #4326 (2025-05-07 14:56:41)

Fix: use maybe_parse for python model depends_on instead of parse_one
This PR fixes a small Python model bug related to how we parse the `depends_on` values. Other than that, it also adds a test that demonstrates how one can manually specify blueprint models as dependencies in Python model definitions.


Patch:
diff --git a/sqlmesh/core/model/definition.py b/sqlmesh/core/model/definition.py
index 3dd73429..d863aff0 100644
--- a/sqlmesh/core/model/definition.py
+++ b/sqlmesh/core/model/definition.py
@@ -2295,7 +2295,7 @@ def create_python_model(
     else:
         depends_on_rendered = render_expression(
             expression=exp.Array(
-                expressions=[d.parse_one(dep, dialect=dialect) for dep in depends_on or []]
+                expressions=[exp.maybe_parse(dep, dialect=dialect) for dep in depends_on or []]
             ),
             module_path=module_path,
             macros=macros,


Test patch:
diff --git a/tests/core/test_model.py b/tests/core/test_model.py
index 3686b354..39110023 100644
--- a/tests/core/test_model.py
+++ b/tests/core/test_model.py
@@ -8845,6 +8845,54 @@ def entrypoint(context, *args, **kwargs):
     assert t.cast(pd.DataFrame, list(m.render(context=context))[0]).to_dict() == {"x": {0: 1}}
 
 
+def test_python_model_depends_on_blueprints(tmp_path: Path) -> None:
+    sql_model = tmp_path / "models" / "base_blueprints.sql"
+    sql_model.parent.mkdir(parents=True, exist_ok=True)
+    sql_model.write_text(
+        """
+        MODEL (
+          name test_schema1.@{model_name},
+          blueprints ((model_name := foo), (model_name := bar)),
+          kind FULL
+        );
+
+        SELECT 1 AS id
+        """
+    )
+
+    py_model = tmp_path / "models" / "depends_on_with_blueprint_vars.py"
+    py_model.parent.mkdir(parents=True, exist_ok=True)
+    py_model.write_text(
+        """
+import pandas as pd
+from sqlmesh import model
+
+@model(
+    "test_schema2.@model_name",
+    columns={
+        "id": "int",
+    },
+    blueprints=[
+        {"model_name": "foo"},
+        {"model_name": "bar"},
+    ],
+    depends_on=["test_schema1.@{model_name}"],
+)
+def entrypoint(context, *args, **kwargs):
+    table = context.resolve_table(f"test_schema1.{context.blueprint_var('model_name')}")
+    return context.fetchdf(f"SELECT * FROM {table}")"""
+    )
+
+    ctx = Context(
+        config=Config(model_defaults=ModelDefaultsConfig(dialect="duckdb")),
+        paths=tmp_path,
+    )
+    assert len(ctx.models) == 4
+
+    ctx.plan(no_prompts=True, auto_apply=True)
+    assert ctx.fetchdf("SELECT * FROM test_schema2.foo").to_dict() == {"id": {0: 1}}
+
+
 @time_machine.travel("2020-01-01 00:00:00 UTC")
 def test_dynamic_date_spine_model(assert_exp_eq):
     @macro()
Repository: TobikoData/sqlmesh
Pull request #4346 (2025-05-08 22:19:39)

Fix: Include the module path when diffing python code


Patch:
diff --git a/sqlmesh/core/model/common.py b/sqlmesh/core/model/common.py
index 61d331f3..310883ff 100644
--- a/sqlmesh/core/model/common.py
+++ b/sqlmesh/core/model/common.py
@@ -361,10 +361,16 @@ def sort_python_env(python_env: t.Dict[str, Executable]) -> t.List[t.Tuple[str,
 
 def sorted_python_env_payloads(python_env: t.Dict[str, Executable]) -> t.List[str]:
     """Returns the payloads of the sorted python env."""
-    return [
-        v.payload if v.is_import or v.is_definition else f"{k} = {v.payload}"
-        for k, v in sort_python_env(python_env)
-    ]
+
+    def _executable_to_str(k: str, v: Executable) -> str:
+        result = f"# {v.path}\n" if v.path is not None else ""
+        if v.is_import or v.is_definition:
+            result += v.payload
+        else:
+            result += f"{k} = {v.payload}"
+        return result
+
+    return [_executable_to_str(k, v) for k, v in sort_python_env(python_env)]
 
 
 expression_validator: t.Callable = field_validator(


Test patch:
diff --git a/tests/core/test_model.py b/tests/core/test_model.py
index 7cf9173c..9565d6d9 100644
--- a/tests/core/test_model.py
+++ b/tests/core/test_model.py
@@ -9702,3 +9702,26 @@ def test_scd_time_data_type_does_not_cause_diff_after_deserialization() -> None:
         deserialized_model = SqlModel.parse_raw(model.json())
 
         assert model.data_hash == deserialized_model.data_hash
+
+
+def test_python_env_includes_file_path_in_render_definition():
+    @model(
+        "db.test_model_path",
+        kind=dict(
+            name=ModelKindName.SCD_TYPE_2_BY_TIME,
+            unique_key=["id"],
+            disable_restatement=False,
+        ),
+        columns={"id": "string", "name": "string"},
+        optimize_query=False,
+    )
+    def test_model(context, **kwargs):
+        return pd.DataFrame([{"id": context.var("1")}])
+
+    python_model = model.get_registry()["db.test_model_path"].model(
+        module_path=Path("."), path=Path("."), dialect="duckdb"
+    )
+
+    model_executable_str = python_model.render_definition()[1].sql()
+    # Make sure the file path is included in the render definition
+    assert "# tests/core/test_model.py" in model_executable_str