gh-149530: Remove symtable.Class.get_methods deprecated method (#149531)

This commit is contained in:
sobolevn 2026-05-09 11:33:09 +03:00 committed by GitHub
parent bc8cf07d8d
commit 46a2c11eaa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 16 additions and 173 deletions

View file

@ -84,7 +84,7 @@ Pending removal in Python 3.16
* :mod:`symtable`:
* The :meth:`Class.get_methods <symtable.Class.get_methods>` method
* The :meth:`!symtable.Class.get_methods` method
has been deprecated since Python 3.14.
* :mod:`sys`:

View file

@ -187,57 +187,6 @@ Examining Symbol Tables
A namespace of a class. This class inherits from :class:`SymbolTable`.
.. method:: get_methods()
Return a tuple containing the names of method-like functions declared
in the class.
Here, the term 'method' designates *any* function defined in the class
body via :keyword:`def` or :keyword:`async def`.
Functions defined in a deeper scope (e.g., in an inner class) are not
picked up by :meth:`get_methods`.
For example:
.. testsetup:: symtable.Class.get_methods
import warnings
context = warnings.catch_warnings()
context.__enter__()
warnings.simplefilter("ignore", category=DeprecationWarning)
.. testcleanup:: symtable.Class.get_methods
context.__exit__()
.. doctest:: symtable.Class.get_methods
>>> import symtable
>>> st = symtable.symtable('''
... def outer(): pass
...
... class A:
... def f():
... def w(): pass
...
... def g(self): pass
...
... @classmethod
... async def h(cls): pass
...
... global outer
... def outer(self): pass
... ''', 'test', 'exec')
>>> class_A = st.get_children()[2]
>>> class_A.get_methods()
('f', 'g', 'h')
Although ``A().f()`` raises :exc:`TypeError` at runtime, ``A.f`` is still
considered as a method-like function.
.. deprecated-removed:: 3.14 3.16
.. class:: Symbol

View file

@ -5,3 +5,6 @@ c-api/allocation.html: deprecated-aliases
c-api/file.html: deprecated-api
library/asyncio-task.html: terminating-a-task-group
# Removed APIs
library/symtable.html: symtable.Class.get_methods

View file

@ -2718,7 +2718,7 @@ New deprecations
(Contributed by Tian Gao in :gh:`124369` and :gh:`125951`.)
* :mod:`symtable`:
Deprecate :meth:`symtable.Class.get_methods` due to the lack of interest,
Deprecate :meth:`!symtable.Class.get_methods` due to the lack of interest,
scheduled for removal in Python 3.16.
(Contributed by Bénédikt Tran in :gh:`119698`.)

View file

@ -120,6 +120,12 @@ functools
* Calling the Python implementation of :func:`functools.reduce` with *function*
or *sequence* as keyword arguments has been deprecated since Python 3.14.
symtable
--------
* The :meth:`!symtable.Class.get_methods` method
which has been deprecated since Python 3.14.
sysconfig
---------

View file

@ -240,41 +240,7 @@ def get_cells(self):
class Class(SymbolTable):
__methods = None
def get_methods(self):
"""Return a tuple of methods declared in the class.
"""
import warnings
typename = f'{self.__class__.__module__}.{self.__class__.__name__}'
warnings.warn(f'{typename}.get_methods() is deprecated '
f'and will be removed in Python 3.16.',
DeprecationWarning, stacklevel=2)
if self.__methods is None:
d = {}
def is_local_symbol(ident):
flags = self._table.symbols.get(ident, 0)
return ((flags >> SCOPE_OFF) & SCOPE_MASK) == LOCAL
for st in self._table.children:
# pick the function-like symbols that are local identifiers
if is_local_symbol(st.name):
match st.type:
case _symtable.TYPE_FUNCTION:
d[st.name] = 1
case _symtable.TYPE_TYPE_PARAMETERS:
# Get the function-def block in the annotation
# scope 'st' with the same identifier, if any.
scope_name = st.name
for c in st.children:
if c.name == scope_name and c.type == _symtable.TYPE_FUNCTION:
d[scope_name] = 1
break
self.__methods = tuple(d)
return self.__methods
pass
class Symbol:

View file

@ -2,8 +2,6 @@
Test the API of the symtable module.
"""
import re
import textwrap
import symtable
import warnings
import unittest
@ -364,87 +362,6 @@ def test_name(self):
self.assertEqual(self.spam.lookup("x").get_name(), "x")
self.assertEqual(self.Mine.get_name(), "Mine")
def test_class_get_methods(self):
deprecation_mess = (
re.escape('symtable.Class.get_methods() is deprecated '
'and will be removed in Python 3.16.')
)
with self.assertWarnsRegex(DeprecationWarning, deprecation_mess):
self.assertEqual(self.Mine.get_methods(), ('a_method',))
top = symtable.symtable(TEST_COMPLEX_CLASS_CODE, "?", "exec")
this = find_block(top, "ComplexClass")
with self.assertWarnsRegex(DeprecationWarning, deprecation_mess):
self.assertEqual(this.get_methods(), (
'a_method', 'a_method_pep_695',
'an_async_method', 'an_async_method_pep_695',
'a_classmethod', 'a_classmethod_pep_695',
'an_async_classmethod', 'an_async_classmethod_pep_695',
'a_staticmethod', 'a_staticmethod_pep_695',
'an_async_staticmethod', 'an_async_staticmethod_pep_695',
'a_fakemethod', 'a_fakemethod_pep_695',
'an_async_fakemethod', 'an_async_fakemethod_pep_695',
'glob_unassigned_meth', 'glob_unassigned_meth_pep_695',
'glob_unassigned_async_meth', 'glob_unassigned_async_meth_pep_695',
'glob_assigned_meth', 'glob_assigned_meth_pep_695',
'glob_assigned_async_meth', 'glob_assigned_async_meth_pep_695',
))
# Test generator expressions that are of type TYPE_FUNCTION
# but will not be reported by get_methods() since they are
# not functions per se.
#
# Other kind of comprehensions such as list, set or dict
# expressions do not have the TYPE_FUNCTION type.
def check_body(body, expected_methods):
indented = textwrap.indent(body, ' ' * 4)
top = symtable.symtable(f"class A:\n{indented}", "?", "exec")
this = find_block(top, "A")
with self.assertWarnsRegex(DeprecationWarning, deprecation_mess):
self.assertEqual(this.get_methods(), expected_methods)
# statements with 'genexpr' inside it
GENEXPRS = (
'x = (x for x in [])',
'x = (x async for x in [])',
'type x[genexpr = (x for x in [])] = (x for x in [])',
'type x[genexpr = (x async for x in [])] = (x async for x in [])',
'genexpr = (x for x in [])',
'genexpr = (x async for x in [])',
'type genexpr[genexpr = (x for x in [])] = (x for x in [])',
'type genexpr[genexpr = (x async for x in [])] = (x async for x in [])',
)
for gen in GENEXPRS:
# test generator expression
with self.subTest(gen=gen):
check_body(gen, ())
# test generator expression + variable named 'genexpr'
with self.subTest(gen=gen, isvar=True):
check_body('\n'.join((gen, 'genexpr = 1')), ())
check_body('\n'.join(('genexpr = 1', gen)), ())
for paramlist in ('()', '(x)', '(x, y)', '(z: T)'):
for func in (
f'def genexpr{paramlist}:pass',
f'async def genexpr{paramlist}:pass',
f'def genexpr[T]{paramlist}:pass',
f'async def genexpr[T]{paramlist}:pass',
):
with self.subTest(func=func):
# test function named 'genexpr'
check_body(func, ('genexpr',))
for gen in GENEXPRS:
with self.subTest(gen=gen, func=func):
# test generator expression + function named 'genexpr'
check_body('\n'.join((gen, func)), ('genexpr',))
check_body('\n'.join((func, gen)), ('genexpr',))
def test_filename_correct(self):
### Bug tickler: SyntaxError file name correct whether error raised
### while parsing or building symbol table.

View file

@ -2038,7 +2038,7 @@ Remove workarounds for non-IEEE 754 systems in :mod:`cmath`.
.. nonce: WlygzR
.. section: Library
Due to the lack of interest for :meth:`symtable.Class.get_methods`, the
Due to the lack of interest for :meth:`!symtable.Class.get_methods`, the
method is marked as deprecated and will be removed in Python 3.16. Patch by
Bénédikt Tran.
@ -2746,7 +2746,7 @@ situations.
.. nonce: rRrprk
.. section: Library
Fix :meth:`symtable.Class.get_methods` and document its behaviour. Patch by
Fix :meth:`!symtable.Class.get_methods` and document its behaviour. Patch by
Bénédikt Tran.
..

View file

@ -0,0 +1,2 @@
Removed :meth:`!symtable.Class.get_methods` which has been deprecated since
3.14.