Skip to content

Commit fbae7c9

Browse files
committed
skip references to the same cell, add tests
1 parent 79ecae2 commit fbae7c9

File tree

2 files changed

+106
-0
lines changed

2 files changed

+106
-0
lines changed

marimo/_runtime/dataflow.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,11 +331,19 @@ def register_cell(self, cell_id: CellId_t, cell: CellImpl) -> None:
331331
if sql_ref:
332332
sql_matches = self._find_sql_hierarchical_matches(sql_ref)
333333
for matching_cell_ids, _ in sql_matches:
334+
if cell_id in matching_cell_ids:
335+
LOGGER.debug(
336+
"Cell %s is referencing itself", cell_id
337+
)
338+
continue
334339
other_ids_defining_name.update(matching_cell_ids)
335340

336341
# If other_ids_defining_name is empty, the user will get a
337342
# NameError at runtime (unless the symbol is a builtin).
338343
for other_id in other_ids_defining_name:
344+
if other_id == cell_id:
345+
LOGGER.error("Cell %s is referencing itself", cell_id)
346+
continue
339347
if not self._is_valid_cell_reference(
340348
other_id, variable_name
341349
):

tests/_runtime/test_dataflow_cases.py

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,104 @@ def __post_init__(self) -> None:
484484
},
485485
expected_defs={"0": ["my_db"], "1": ["my_table"], "2": [], "3": []},
486486
),
487+
GraphTestCase(
488+
name="create table with the same name from a different schema",
489+
enabled=HAS_DUCKDB,
490+
code={
491+
"0": "_ = mo.sql(f'CREATE TABLE my_table AS SELECT * FROM schema_one.my_table')",
492+
"1": "_ = mo.sql(f'SELECT * FROM my_table')",
493+
},
494+
expected_parents={"0": [], "1": ["0"]},
495+
expected_children={"0": ["1"], "1": []},
496+
expected_refs={
497+
"0": ["mo", "schema_one.my_table"],
498+
"1": ["mo", "my_table"],
499+
},
500+
expected_defs={"0": ["my_table"], "1": []},
501+
),
502+
GraphTestCase(
503+
name="create table with the same name from catalog.schema hierarchy",
504+
enabled=HAS_DUCKDB,
505+
code={
506+
"0": "_ = mo.sql(f'CREATE TABLE my_table AS SELECT * FROM catalog_one.schema_one.my_table')",
507+
"1": "_ = mo.sql(f'SELECT * FROM my_table')",
508+
},
509+
expected_parents={"0": [], "1": ["0"]},
510+
expected_children={"0": ["1"], "1": []},
511+
expected_refs={
512+
"0": ["mo", "catalog_one.schema_one.my_table"],
513+
"1": ["mo", "my_table"],
514+
},
515+
expected_defs={"0": ["my_table"], "1": []},
516+
),
517+
GraphTestCase(
518+
name="create schema with the same name from a different catalog",
519+
enabled=HAS_DUCKDB,
520+
code={
521+
"0": "_ = mo.sql(f'CREATE SCHEMA my_schema')",
522+
"1": "_ = mo.sql(f'CREATE TABLE my_schema.my_table AS SELECT * FROM catalog_one.my_schema.my_table')",
523+
"2": "_ = mo.sql(f'SELECT * FROM my_schema.my_table')",
524+
},
525+
expected_parents={"0": [], "1": ["0"], "2": ["0", "1"]},
526+
expected_children={"0": ["1", "2"], "1": ["2"], "2": []},
527+
expected_refs={
528+
"0": ["mo"],
529+
"1": ["mo", "catalog_one.my_schema.my_table", "my_schema"],
530+
"2": ["mo", "my_schema.my_table"],
531+
},
532+
expected_defs={"0": ["my_schema"], "1": ["my_table"], "2": []},
533+
),
534+
GraphTestCase(
535+
name="create table that references itself in join prevents self-loop",
536+
enabled=HAS_DUCKDB,
537+
code={
538+
"0": "_ = mo.sql(f'CREATE TABLE users AS SELECT 1 as id')",
539+
"1": "_ = mo.sql(f'CREATE TABLE orders AS SELECT u.id FROM schema_one.users u JOIN schema_two.orders o ON u.id = o.user_id')",
540+
"2": "_ = mo.sql(f'SELECT * FROM orders')",
541+
},
542+
expected_parents={"0": [], "1": [], "2": ["1"]},
543+
expected_children={"0": [], "1": ["2"], "2": []},
544+
expected_refs={
545+
"0": ["mo"],
546+
"1": ["mo", "schema_one.users", "schema_two.orders"],
547+
"2": ["mo", "orders"],
548+
},
549+
expected_defs={"0": ["users"], "1": ["orders"], "2": []},
550+
),
551+
GraphTestCase(
552+
name="multiple tables with hierarchical self-reference patterns",
553+
enabled=HAS_DUCKDB,
554+
code={
555+
"0": "_ = mo.sql(f'CREATE TABLE table_a AS SELECT * FROM db1.table_a')",
556+
"1": "_ = mo.sql(f'CREATE TABLE table_b AS SELECT * FROM db2.table_b')",
557+
"2": "_ = mo.sql(f'SELECT * FROM table_a UNION ALL SELECT * FROM table_b')",
558+
},
559+
expected_parents={"0": [], "1": [], "2": ["0", "1"]},
560+
expected_children={"0": ["2"], "1": ["2"], "2": []},
561+
expected_refs={
562+
"0": ["mo", "db1.table_a"],
563+
"1": ["mo", "db2.table_b"],
564+
"2": ["mo", "table_a", "table_b"],
565+
},
566+
expected_defs={"0": ["table_a"], "1": ["table_b"], "2": []},
567+
),
568+
GraphTestCase(
569+
name="create table from hierarchical ref then reference it hierarchically",
570+
enabled=HAS_DUCKDB,
571+
code={
572+
"0": "_ = mo.sql(f'CREATE SCHEMA my_schema')",
573+
"1": "_ = mo.sql(f'CREATE TABLE my_schema.data AS SELECT * FROM external.my_schema.data')",
574+
"2": "_ = mo.sql(f'SELECT * FROM my_schema.data')",
575+
},
576+
expected_parents={"0": [], "1": ["0"], "2": ["0", "1"]},
577+
expected_children={"0": ["1", "2"], "1": ["2"], "2": []},
578+
expected_refs={
579+
"0": ["mo"],
580+
"1": ["mo", "external.my_schema.data", "my_schema"],
581+
"2": ["mo", "my_schema.data"],
582+
},
583+
expected_defs={"0": ["my_schema"], "1": ["data"], "2": []},
584+
),
487585
GraphTestCase(
488586
name="sql table multiple definitions, different order",
489587
enabled=HAS_DUCKDB,

0 commit comments

Comments
 (0)