diff --git a/Lib/symtable.py b/Lib/symtable.py index 4c832e68f94cbd..33c8d0bd23efa1 100644 --- a/Lib/symtable.py +++ b/Lib/symtable.py @@ -184,6 +184,7 @@ class Function(SymbolTable): __frees = None __globals = None __nonlocals = None + __cells = None def __idents_matching(self, test_func): return tuple(ident for ident in self.get_identifiers() @@ -229,6 +230,13 @@ 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. + """ + if self.__cells is None: + self.__cells = [s.get_name() for s in self.get_symbols() if s.is_cell()] + return self.__cells + class Class(SymbolTable): @@ -342,6 +350,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..8e5af65385ede2 100644 --- a/Lib/test/test_symtable.py +++ b/Lib/test/test_symtable.py @@ -284,6 +284,10 @@ def test_local(self): def test_free(self): self.assertTrue(self.internal.lookup("x").is_free()) + def test_cells(self): + self.assertTrue(self.spam.lookup("x").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.