Skip to content

library symtable.SymbolTable.is_nested() description differs from Cpython implementation. #99350

Open

Description

@mrolle45

The documentation says

is_nested()
Return True if the block is a nested class or function.

The cpython implementation of symtable.c sets the corresponding flag only if the block is nested somewhere inside a function. This would include, for example, a scope inside a class inside a function.

Thus

def f():    # false
  def g():    # true
    def h():    # true
    class C:    # true
  class B:    # true
    def h():    # true
    class C:    # true
class A:    # false
  def g():    # false !!
    def h():    # true
    class C:    # true
  class B:    # false !!
    def h():    # false !!
    class C:    # false !!

The value is the same as the CO_NESTED bit in the code object's co_flags member.
The flag is also documented (similarly incorrectly) in the inspect module documentation.

I would recommend deprecating this feature. The documentation for co_flags says that

bits 0x10 and 0x1000 were used in earlier versions of Python.

0x10 is the CO_NESTED bit. I would guess that nobody uses CO_NESTED or SymbolTable.is_nested().

Alternatives:

  • Change the behavior in Cpython to agree with the documentation. A class nested in another scope should also have CO_NESTED set. Make a test case for the compiler, to ensure that other implementations follow the same definition.
  • Correct the documentation for symtable and inspect modules. Possibly also deprecate the feature.

Linked PRs

Activity

  1. MonadChains commented on Nov 12, 2022

    @MonadChains
    Contributor

    Discussion about possible deprecation of CO_NESTED: #96811
    There is also a previous PR opened on the subject #19660

  2. added
    docsDocumentation in the Doc dir
    stdlibStandard Library Python modules in the Lib/ directory
    on Nov 27, 2023
  3. johnslavik commented on Aug 17, 2025

    @johnslavik
    Member

    Yes, the deprecation of CO_NESTED was rejected in #96811.
    However, it would still be useful to update the docs of the flag as it does not only flag nested functions, but all function-like blocks only (that includes nested type statements, nested generator comprehensions, nested sets of type parameters to generic functions which "wrap" regular function code objects, set/list/dict comprehensions until 3.11 etc.)
    It's still true that CO_NESTED doesn't mark nested classes; neither when they're nested in a function nor in another class.

    import inspect, pprint
    
    def examples():
        type NestedAnn = complex
    
        (() for () in ())
    
        def nested_generic[T](x: T) -> T:
            pass
    
        def nested_func():
            pass
    
        class NestedClass:
            pass
    
    pprint.pprint(
        {
            const.co_name: const.co_flags
            for const in examples.__code__.co_consts
            if inspect.iscode(const)
        }
    )

    This prints:

    {'<generic parameters of nested_generic>': 19,
     '<genexpr>': 51,
     'NestedAnn': 19,
     'NestedClass': 0,
     'nested_func': 19}

    A documentation update would be great, I'll try to make one.

  4. picnixz commented on Aug 17, 2025

    @picnixz
    Member

    I think it would be just better to fix symtable actually. For introspection it could be the only way to do it properly and in a compatible manner, at least assuming CPython implementation. The rationale for rejecting the deprecation is because it is useful for others.

  5. added
    type-bugAn unexpected behavior, bug, or error
    interpreter-core(Objects, Python, Grammar, and Parser dirs)
    and removed
    stdlibStandard Library Python modules in the Lib/ directory
    on Aug 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    docsDocumentation in the Doc dirinterpreter-core(Objects, Python, Grammar, and Parser dirs)type-bugAn unexpected behavior, bug, or error

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions