mirror of
https://github.com/python/cpython.git
synced 2026-06-05 01:10:53 +00:00
gh-149530: Remove symtable.Class.get_methods deprecated method (#149531)
This commit is contained in:
parent
bc8cf07d8d
commit
46a2c11eaa
9 changed files with 16 additions and 173 deletions
|
|
@ -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`:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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`.)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
---------
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
..
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
Removed :meth:`!symtable.Class.get_methods` which has been deprecated since
|
||||
3.14.
|
||||
Loading…
Add table
Add a link
Reference in a new issue