gh-110045: Update symtable module for PEP 695 (#110066)

This commit is contained in:
Jelle Zijlstra 2023-09-28 19:08:04 -07:00 committed by GitHub
parent 2e37a38bcb
commit 7dc2c5093e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 63 additions and 5 deletions

View File

@ -38,7 +38,13 @@ Examining Symbol Tables
.. method:: get_type()
Return the type of the symbol table. Possible values are ``'class'``,
``'module'``, and ``'function'``.
``'module'``, ``'function'``, ``'annotation'``, ``'TypeVar bound'``,
``'type alias'``, and ``'type parameter'``. The latter four refer to
different flavors of :ref:`annotation scopes <annotation-scopes>`.
.. versionchanged:: 3.12
Added ``'annotation'``, ``'TypeVar bound'``, ``'type alias'``,
and ``'type parameter'`` as possible return values.
.. method:: get_id()
@ -49,6 +55,10 @@ Examining Symbol Tables
Return the table's name. This is the name of the class if the table is
for a class, the name of the function if the table is for a function, or
``'top'`` if the table is global (:meth:`get_type` returns ``'module'``).
For type parameter scopes (which are used for generic classes, functions,
and type aliases), it is the name of the underlying class, function, or
type alias. For type alias scopes, it is the name of the type alias.
For :class:`~typing.TypeVar` bound scopes, it is the name of the ``TypeVar``.
.. method:: get_lineno()

View File

@ -62,8 +62,8 @@ class SymbolTable:
def get_type(self):
"""Return the type of the symbol table.
The values returned are 'class', 'module' and
'function'.
The values returned are 'class', 'module', 'function',
'annotation', 'TypeVar bound', 'type alias', and 'type parameter'.
"""
if self._table.type == _symtable.TYPE_MODULE:
return "module"
@ -71,8 +71,15 @@ class SymbolTable:
return "function"
if self._table.type == _symtable.TYPE_CLASS:
return "class"
assert self._table.type in (1, 2, 3), \
"unexpected type: {0}".format(self._table.type)
if self._table.type == _symtable.TYPE_ANNOTATION:
return "annotation"
if self._table.type == _symtable.TYPE_TYPE_VAR_BOUND:
return "TypeVar bound"
if self._table.type == _symtable.TYPE_TYPE_ALIAS:
return "type alias"
if self._table.type == _symtable.TYPE_TYPE_PARAM:
return "type parameter"
assert False, f"unexpected type: {self._table.type}"
def get_id(self):
"""Return an identifier for the table.

View File

@ -40,6 +40,15 @@ def foo():
def namespace_test(): pass
def namespace_test(): pass
type Alias = int
type GenericAlias[T] = list[T]
def generic_spam[T](a):
pass
class GenericMine[T: int]:
pass
"""
@ -59,6 +68,14 @@ class SymtableTest(unittest.TestCase):
internal = find_block(spam, "internal")
other_internal = find_block(spam, "other_internal")
foo = find_block(top, "foo")
Alias = find_block(top, "Alias")
GenericAlias = find_block(top, "GenericAlias")
GenericAlias_inner = find_block(GenericAlias, "GenericAlias")
generic_spam = find_block(top, "generic_spam")
generic_spam_inner = find_block(generic_spam, "generic_spam")
GenericMine = find_block(top, "GenericMine")
GenericMine_inner = find_block(GenericMine, "GenericMine")
T = find_block(GenericMine, "T")
def test_type(self):
self.assertEqual(self.top.get_type(), "module")
@ -66,6 +83,15 @@ class SymtableTest(unittest.TestCase):
self.assertEqual(self.a_method.get_type(), "function")
self.assertEqual(self.spam.get_type(), "function")
self.assertEqual(self.internal.get_type(), "function")
self.assertEqual(self.foo.get_type(), "function")
self.assertEqual(self.Alias.get_type(), "type alias")
self.assertEqual(self.GenericAlias.get_type(), "type parameter")
self.assertEqual(self.GenericAlias_inner.get_type(), "type alias")
self.assertEqual(self.generic_spam.get_type(), "type parameter")
self.assertEqual(self.generic_spam_inner.get_type(), "function")
self.assertEqual(self.GenericMine.get_type(), "type parameter")
self.assertEqual(self.GenericMine_inner.get_type(), "class")
self.assertEqual(self.T.get_type(), "TypeVar bound")
def test_id(self):
self.assertGreater(self.top.get_id(), 0)
@ -73,6 +99,11 @@ class SymtableTest(unittest.TestCase):
self.assertGreater(self.a_method.get_id(), 0)
self.assertGreater(self.spam.get_id(), 0)
self.assertGreater(self.internal.get_id(), 0)
self.assertGreater(self.foo.get_id(), 0)
self.assertGreater(self.Alias.get_id(), 0)
self.assertGreater(self.GenericAlias.get_id(), 0)
self.assertGreater(self.generic_spam.get_id(), 0)
self.assertGreater(self.GenericMine.get_id(), 0)
def test_optimized(self):
self.assertFalse(self.top.is_optimized())

View File

@ -0,0 +1,2 @@
Update the :mod:`symtable` module to support the new scopes introduced by
:pep:`695`.

View File

@ -86,6 +86,14 @@ symtable_init_constants(PyObject *m)
if (PyModule_AddIntConstant(m, "TYPE_CLASS", ClassBlock) < 0) return -1;
if (PyModule_AddIntConstant(m, "TYPE_MODULE", ModuleBlock) < 0)
return -1;
if (PyModule_AddIntConstant(m, "TYPE_ANNOTATION", AnnotationBlock) < 0)
return -1;
if (PyModule_AddIntConstant(m, "TYPE_TYPE_VAR_BOUND", TypeVarBoundBlock) < 0)
return -1;
if (PyModule_AddIntConstant(m, "TYPE_TYPE_ALIAS", TypeAliasBlock) < 0)
return -1;
if (PyModule_AddIntConstant(m, "TYPE_TYPE_PARAM", TypeParamBlock) < 0)
return -1;
if (PyModule_AddIntMacro(m, LOCAL) < 0) return -1;
if (PyModule_AddIntMacro(m, GLOBAL_EXPLICIT) < 0) return -1;