diff --git a/Lib/symtable.py b/Lib/symtable.py index 4c832e68f94cbd..544211c98a6f62 100644 --- a/Lib/symtable.py +++ b/Lib/symtable.py @@ -229,6 +229,10 @@ def get_frees(self): self.__frees = self.__idents_matching(is_free) return self.__frees + def get_cells(self): + """Return a list of cell variable names in the table.""" + return [s.get_name() for s in self.get_symbols() if s.is_cell()] + class Class(SymbolTable): @@ -342,6 +346,10 @@ def is_free(self): """ return bool(self.__scope == FREE) + def is_cell(self): + """Return *True* if the symbol is a cell variable.""" + return bool(self.__scope == CELL) + def is_free_class(self): """Return *True* if a class-scoped symbol is free from the perspective of a method.""" diff --git a/Lib/test/test_symtable.py b/Lib/test/test_symtable.py index 094ab8f573e7ba..164e1068a6b1db 100644 --- a/Lib/test/test_symtable.py +++ b/Lib/test/test_symtable.py @@ -284,6 +284,20 @@ def test_local(self): def test_free(self): self.assertTrue(self.internal.lookup("x").is_free()) + def test_cells(self): + #test for addition of is_cell() and get_cells() + #see https://github.com/python/cpython/issues/143504 + code="""def outer(): + x=1 + def inner(): + return x""" + + top=symtable.symtable(code,"?","exec") + outer = find_block(top, "outer") + self.assertIn("x",outer.get_cells()) + self.assertTrue(outer.lookup("x").is_cell()) + self.assertFalse(outer.lookup("inner").is_cell()) + def test_referenced(self): self.assertTrue(self.internal.lookup("x").is_referenced()) self.assertTrue(self.spam.lookup("internal").is_referenced()) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-01-08-16-28-03.gh-issue-143504.PlC_Yv.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-08-16-28-03.gh-issue-143504.PlC_Yv.rst new file mode 100644 index 00000000000000..a4692f9c36777a --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-08-16-28-03.gh-issue-143504.PlC_Yv.rst @@ -0,0 +1 @@ +Add symtable.is_cell() and get_cells() methods for cell variable analysis.