File tree Expand file tree Collapse file tree 3 files changed +124
-1
lines changed Expand file tree Collapse file tree 3 files changed +124
-1
lines changed Original file line number Diff line number Diff line change @@ -531,7 +531,12 @@ def _visit_and_get_refs(
531531 # Thus, if it has been declared, it's not "unbounded"
532532 class_def .add (var )
533533 else :
534- unbounded_refs |= data .required_refs
534+ # For non-function/non-class variables (e.g., class attributes),
535+ # exclude references to variables already defined in class scope
536+ unbounded_refs |= data .required_refs - class_def
537+ # Add the variable to class_def so that later references
538+ # to it don't create unbounded refs
539+ class_def .add (var )
535540 unbounded_refs |= mock_visitor .refs - ignore_refs
536541
537542 # Handle function/class refs that are evaluated in the outer scope
Original file line number Diff line number Diff line change 1+ import marimo
2+
3+ __generated_with = "0.18.0"
4+ app = marimo .App (width = "medium" )
5+
6+
7+ @app .class_definition
8+ # This should be reusable
9+ class One :
10+ A : int = 1
11+
12+ def run (a : A = 1 ) -> int :
13+ return a
14+
15+
16+ @app .class_definition
17+ # This should be a pure-class
18+ class Two :
19+ A : int = 1
20+
21+ def run (a : int = 1 ) -> int :
22+ return a
23+
24+
25+ @app .cell
26+ def _ ():
27+ C = int
28+ return (C ,)
29+
30+
31+ @app .cell
32+ def _ ():
33+ value = 1
34+ return (value ,)
35+
36+
37+ @app .cell
38+ def _ (C ):
39+ # This should NOT be reusable (depends on C)
40+ class Three :
41+ A : int = 1
42+ B : int = 1
43+
44+ def run (a : C = 1 ) -> int :
45+ return a
46+ return
47+
48+
49+ @app .cell
50+ def _ (C ):
51+ # This should NOT be reusable (depends on C)
52+ class Four :
53+ A : int = 1
54+ B : C = 1
55+
56+ def run (a : B = 1 ) -> int :
57+ return a
58+ return
59+
60+
61+ @app .cell
62+ def _ (value ):
63+ # This should NOT be reusable (depends on value)
64+ class Five :
65+ A : int = 1
66+
67+ def run (a : A = value ) -> int :
68+ return a
69+ return
70+
71+
72+ if __name__ == "__main__" :
73+ app .run ()
Original file line number Diff line number Diff line change @@ -1593,3 +1593,48 @@ def test_sql_pivot_unpivot_commands(
15931593
15941594 assert v .defs == {"df" }, f"Failed for: { description } "
15951595 assert v .refs == expected_refs , f"Failed for: { description } "
1596+
1597+
1598+ def test_class_with_class_var_in_method_default () -> None :
1599+ """Test that class variables used in method defaults don't create unbounded refs (issue #7265)."""
1600+ code = cleandoc (
1601+ """
1602+ class K:
1603+ A: int = 1
1604+ def b(a: int = A) -> int:
1605+ return a
1606+ """
1607+ )
1608+ v = visitor .ScopedVisitor ()
1609+ mod = ast .parse (code )
1610+ v .visit (mod )
1611+
1612+ # K should be a def
1613+ assert v .defs == set (["K" ])
1614+ # A should NOT be a ref (it's defined in class scope), but int is (type annotation)
1615+ assert v .refs == set (["int" ])
1616+ # K should have unbounded_refs only for int, not A
1617+ assert v .variable_data ["K" ][0 ].unbounded_refs == set (["int" ])
1618+
1619+
1620+ def test_class_with_class_var_referencing_another () -> None :
1621+ """Test that class variables used in other class variable definitions don't create unbounded refs (issue #7265)."""
1622+ code = cleandoc (
1623+ """
1624+ class K:
1625+ A: int = 1
1626+ B: int = A
1627+ def b(a: int = B) -> int:
1628+ return a
1629+ """
1630+ )
1631+ v = visitor .ScopedVisitor ()
1632+ mod = ast .parse (code )
1633+ v .visit (mod )
1634+
1635+ # K should be a def
1636+ assert v .defs == set (["K" ])
1637+ # A should NOT be a ref (it's defined in class scope), but int is (type annotation)
1638+ assert v .refs == set (["int" ])
1639+ # K should have unbounded_refs only for int, not A
1640+ assert v .variable_data ["K" ][0 ].unbounded_refs == set (["int" ])
You can’t perform that action at this time.
0 commit comments