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
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:
Test the API of the symtable module.
"""
-import re
-import textwrap
import symtable
import warnings
import unittest
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.