diff --git a/Doc/deprecations/pending-removal-in-3.16.rst b/Doc/deprecations/pending-removal-in-3.16.rst index b00c7002b03772..a64212e38e61cb 100644 --- a/Doc/deprecations/pending-removal-in-3.16.rst +++ b/Doc/deprecations/pending-removal-in-3.16.rst @@ -84,7 +84,7 @@ Pending removal in Python 3.16 * :mod:`symtable`: - * The :meth:`Class.get_methods ` method + * The :meth:`!symtable.Class.get_methods` method has been deprecated since Python 3.14. * :mod:`sys`: diff --git a/Doc/library/symtable.rst b/Doc/library/symtable.rst index 52a722608db431..95f20b06b5aa1e 100644 --- a/Doc/library/symtable.rst +++ b/Doc/library/symtable.rst @@ -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 diff --git a/Doc/tools/removed-ids.txt b/Doc/tools/removed-ids.txt index 5e3ef2efe271fd..adac1b993047bc 100644 --- a/Doc/tools/removed-ids.txt +++ b/Doc/tools/removed-ids.txt @@ -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 \ No newline at end of file diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 0bb8858aea16fe..39d1d8da5367e5 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -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`.) diff --git a/Doc/whatsnew/3.16.rst b/Doc/whatsnew/3.16.rst index 4ddc836d9b29e4..d9beda92aba6a3 100644 --- a/Doc/whatsnew/3.16.rst +++ b/Doc/whatsnew/3.16.rst @@ -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 --------- diff --git a/Lib/symtable.py b/Lib/symtable.py index c7152a70f5aa0b..9238437191c00f 100644 --- a/Lib/symtable.py +++ b/Lib/symtable.py @@ -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: diff --git a/Lib/test/test_symtable.py b/Lib/test/test_symtable.py index c748243110df9f..8c03420c4c5e4b 100644 --- a/Lib/test/test_symtable.py +++ b/Lib/test/test_symtable.py @@ -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. diff --git a/Misc/NEWS.d/3.14.0a1.rst b/Misc/NEWS.d/3.14.0a1.rst index 5303bd89efff5b..79936955757280 100644 --- a/Misc/NEWS.d/3.14.0a1.rst +++ b/Misc/NEWS.d/3.14.0a1.rst @@ -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. .. diff --git a/Misc/NEWS.d/next/Library/2026-05-08-06-56-57.gh-issue-149530.cl2AJ8.rst b/Misc/NEWS.d/next/Library/2026-05-08-06-56-57.gh-issue-149530.cl2AJ8.rst new file mode 100644 index 00000000000000..2b74e8cdadd03c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-08-06-56-57.gh-issue-149530.cl2AJ8.rst @@ -0,0 +1,2 @@ +Removed :meth:`!symtable.Class.get_methods` which has been deprecated since +3.14.