Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Doc/deprecations/pending-removal-in-3.16.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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`:
Expand Down
51 changes: 0 additions & 51 deletions Doc/library/symtable.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
1 change: 1 addition & 0 deletions Doc/tools/removed-ids.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ c-api/allocation.html: deprecated-aliases
c-api/file.html: deprecated-api

library/asyncio-task.html: terminating-a-task-group
library/symtable.html: symtable.Class.get_methods
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
library/symtable.html: symtable.Class.get_methods
# Removed APIs
library/symtable.html: symtable.Class.get_methods

To try and introduce some order to the file.

2 changes: 1 addition & 1 deletion Doc/whatsnew/3.14.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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`.)

Expand Down
6 changes: 6 additions & 0 deletions Doc/whatsnew/3.16.rst
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,12 @@ annotationlib
Use :meth:`annotationlib.ForwardRef.evaluate`
or :func:`typing.evaluate_forward_ref` instead.

symtable
--------

* The :meth:`!symtable.Class.get_methods` method
which has been deprecated since Python 3.14.

sysconfig
---------

Expand Down
36 changes: 1 addition & 35 deletions Lib/symtable.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
83 changes: 0 additions & 83 deletions Lib/test/test_symtable.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
Test the API of the symtable module.
"""

import re
import textwrap
import symtable
import warnings
import unittest
Expand Down Expand Up @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions Misc/NEWS.d/3.14.0a1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -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.

..
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Removed :meth:`!symtable.Class.get_methods` which has been deprecated since
3.14.
Loading