Skip to content

bpo-41224: Document is_annotated() in symtable module and update doc strings #21369

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 7, 2020
Merged
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
4 changes: 4 additions & 0 deletions Doc/library/symtable.rst
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,10 @@ Examining Symbol Tables

Return ``True`` if the symbol is local to its block.

.. method:: is_annotated()

Return ``True`` if the symbol is annotated.

.. method:: is_free()

Return ``True`` if the symbol is referenced in its block, but not assigned
Expand Down
78 changes: 76 additions & 2 deletions Lib/symtable.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
__all__ = ["symtable", "SymbolTable", "Class", "Function", "Symbol"]

def symtable(code, filename, compile_type):
""" Return the toplevel *SymbolTable* for the source code.

*filename* is the name of the file with the code
and *compile_type* is the *compile()* mode argument.
"""
top = _symtable.symtable(code, filename, compile_type)
return _newSymbolTable(top, filename)

Expand Down Expand Up @@ -55,6 +60,11 @@ def __repr__(self):
self._filename)

def get_type(self):
"""Return the type of the symbol table.

The values retuned are 'class', 'module' and
'function'.
"""
if self._table.type == _symtable.TYPE_MODULE:
return "module"
if self._table.type == _symtable.TYPE_FUNCTION:
Expand All @@ -65,27 +75,51 @@ def get_type(self):
"unexpected type: {0}".format(self._table.type)

def get_id(self):
"""Return an identifier for the table.
"""
return self._table.id

def get_name(self):
"""Return the table's name.

This corresponds to the name of the class, function
or 'top' if the table is for a class, function or
global respectively.
"""
return self._table.name

def get_lineno(self):
"""Return the number of the first line in the
block for the table.
"""
return self._table.lineno

def is_optimized(self):
"""Return *True* if the locals in the table
are optimizable.
"""
return bool(self._table.type == _symtable.TYPE_FUNCTION)

def is_nested(self):
"""Return *True* if the block is a nested class
or function."""
return bool(self._table.nested)

def has_children(self):
"""Return *True* if the block has nested namespaces.
"""
return bool(self._table.children)

def get_identifiers(self):
"""Return a list of names of symbols in the table.
"""
return self._table.symbols.keys()

def lookup(self, name):
"""Lookup a *name* in the table.

Returns a *Symbol* instance.
"""
sym = self._symbols.get(name)
if sym is None:
flags = self._table.symbols[name]
Expand All @@ -94,6 +128,9 @@ def lookup(self, name):
return sym

def get_symbols(self):
"""Return a list of *Symbol* instances for
names in the table.
"""
return [self.lookup(ident) for ident in self.get_identifiers()]

def __check_children(self, name):
Expand All @@ -102,6 +139,8 @@ def __check_children(self, name):
if st.name == name]

def get_children(self):
"""Return a list of the nested symbol tables.
"""
return [_newSymbolTable(st, self._filename)
for st in self._table.children]

Expand All @@ -120,30 +159,40 @@ def __idents_matching(self, test_func):
if test_func(self._table.symbols[ident]))

def get_parameters(self):
"""Return a tuple of parameters to the function.
"""
if self.__params is None:
self.__params = self.__idents_matching(lambda x:x & DEF_PARAM)
return self.__params

def get_locals(self):
"""Return a tuple of locals in the function.
"""
if self.__locals is None:
locs = (LOCAL, CELL)
test = lambda x: ((x >> SCOPE_OFF) & SCOPE_MASK) in locs
self.__locals = self.__idents_matching(test)
return self.__locals

def get_globals(self):
"""Return a tuple of globals in the function.
"""
if self.__globals is None:
glob = (GLOBAL_IMPLICIT, GLOBAL_EXPLICIT)
test = lambda x:((x >> SCOPE_OFF) & SCOPE_MASK) in glob
self.__globals = self.__idents_matching(test)
return self.__globals

def get_nonlocals(self):
"""Return a tuple of nonlocals in the function.
"""
if self.__nonlocals is None:
self.__nonlocals = self.__idents_matching(lambda x:x & DEF_NONLOCAL)
return self.__nonlocals

def get_frees(self):
"""Return a tuple of free variables in the function.
"""
if self.__frees is None:
is_free = lambda x:((x >> SCOPE_OFF) & SCOPE_MASK) == FREE
self.__frees = self.__idents_matching(is_free)
Expand All @@ -155,6 +204,8 @@ class Class(SymbolTable):
__methods = None

def get_methods(self):
"""Return a tuple of methods declared in the class.
"""
if self.__methods is None:
d = {}
for st in self._table.children:
Expand All @@ -175,40 +226,63 @@ def __repr__(self):
return "<symbol {0!r}>".format(self.__name)

def get_name(self):
"""Return a name of a symbol.
"""
return self.__name

def is_referenced(self):
"""Return *True* if the symbol is used in
its block.
"""
return bool(self.__flags & _symtable.USE)

def is_parameter(self):
"""Return *True* if the symbol is a parameter.
"""
return bool(self.__flags & DEF_PARAM)

def is_global(self):
"""Return *True* if the sysmbol is global.
"""
return bool(self.__scope in (GLOBAL_IMPLICIT, GLOBAL_EXPLICIT))

def is_nonlocal(self):
"""Return *True* if the symbol is nonlocal."""
return bool(self.__flags & DEF_NONLOCAL)

def is_declared_global(self):
"""Return *True* if the symbol is declared global
with a global statement."""
return bool(self.__scope == GLOBAL_EXPLICIT)

def is_local(self):
"""Return *True* if the symbol is local.
"""
return bool(self.__scope in (LOCAL, CELL))

def is_annotated(self):
"""Return *True* if the symbol is annotated.
"""
return bool(self.__flags & DEF_ANNOT)

def is_free(self):
"""Return *True* if a referenced symbol is
not assigned to.
"""
return bool(self.__scope == FREE)

def is_imported(self):
"""Return *True* if the symbol is created from
an import statement.
"""
return bool(self.__flags & DEF_IMPORT)

def is_assigned(self):
"""Return *True* if a symbol is assigned to."""
return bool(self.__flags & DEF_LOCAL)

def is_namespace(self):
"""Returns true if name binding introduces new namespace.
"""Returns *True* if name binding introduces new namespace.

If the name is used as the target of a function or class
statement, this will be true.
Expand All @@ -225,7 +299,7 @@ def get_namespaces(self):
return self.__namespaces

def get_namespace(self):
"""Returns the single namespace bound to this name.
"""Return the single namespace bound to this name.

Raises ValueError if the name is bound to multiple namespaces.
"""
Expand Down