https://github.com/python/cpython/commit/a51bf70f95ccab420fb6afec009e8192065f2beb
commit: a51bf70f95ccab420fb6afec009e8192065f2beb
branch: main
author: Yashraj <[email protected]>
committer: iritkatriel <[email protected]>
date: 2026-01-25T15:21:27Z
summary:
gh-143504: Expose CELL status of a symbol in symtable (#143549)
files:
A Misc/NEWS.d/next/Library/2026-01-24-13-49-05.gh-issue-143594.nilGlg.rst
M Doc/library/symtable.rst
M Doc/whatsnew/3.15.rst
M Lib/symtable.py
M Lib/test/test_symtable.py
diff --git a/Doc/library/symtable.rst b/Doc/library/symtable.rst
index f5e6f9f8acfdb8..0b722d7d4e35cf 100644
--- a/Doc/library/symtable.rst
+++ b/Doc/library/symtable.rst
@@ -180,6 +180,12 @@ Examining Symbol Tables
Return a tuple containing names of :term:`free (closure) variables
<closure variable>`
in this function.
+ .. method:: get_cells()
+
+ Return a tuple containing names of :term:`cell variables <closure
variable>` in this table.
+
+ .. versionadded:: next
+
.. class:: Class
@@ -291,6 +297,12 @@ Examining Symbol Tables
Return ``True`` if the symbol is referenced in its block, but not
assigned
to.
+ .. method:: is_cell()
+
+ Return ``True`` if the symbol is referenced but not assigned in a nested
block.
+
+ .. versionadded:: next
+
.. method:: is_free_class()
Return *True* if a class-scoped symbol is free from
diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst
index 8c92ac8e0319da..8c3223d9a784a1 100644
--- a/Doc/whatsnew/3.15.rst
+++ b/Doc/whatsnew/3.15.rst
@@ -737,6 +737,13 @@ ssl
(Contributed by Ron Frederick in :gh:`138252`.)
+symtable
+--------
+
+* Add :meth:`symtable.Function.get_cells` and :meth:`symtable.Symbol.is_cell`
methods.
+ (Contributed by Yashp002 in :gh:`143504`.)
+
+
sys
---
diff --git a/Lib/symtable.py b/Lib/symtable.py
index 4c832e68f94cbd..45610fd5612995 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,14 @@ def get_frees(self):
self.__frees = self.__idents_matching(is_free)
return self.__frees
+ def get_cells(self):
+ """Return a tuple of cell variables in the function.
+ """
+ if self.__cells is None:
+ is_cell = lambda x: _get_scope(x) == CELL
+ self.__cells = self.__idents_matching(is_cell)
+ return self.__cells
+
class Class(SymbolTable):
@@ -342,6 +351,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..c748243110df9f 100644
--- a/Lib/test/test_symtable.py
+++ b/Lib/test/test_symtable.py
@@ -255,6 +255,7 @@ def test_function_info(self):
self.assertEqual(sorted(func.get_locals()), expected)
self.assertEqual(sorted(func.get_globals()), ["bar", "glob",
"some_assigned_global_var"])
self.assertEqual(self.internal.get_frees(), ("x",))
+ self.assertEqual(self.spam.get_cells(), ("some_var", "x",))
def test_globals(self):
self.assertTrue(self.spam.lookup("glob").is_global())
@@ -284,6 +285,9 @@ 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/Library/2026-01-24-13-49-05.gh-issue-143594.nilGlg.rst
b/Misc/NEWS.d/next/Library/2026-01-24-13-49-05.gh-issue-143594.nilGlg.rst
new file mode 100644
index 00000000000000..e0c2c287f57271
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-01-24-13-49-05.gh-issue-143594.nilGlg.rst
@@ -0,0 +1 @@
+Add :meth:`symtable.Function.get_cells` and :meth:`symtable.Symbol.is_cell`
methods.
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]