Skip to content

inspect.BlockFinder handles tokenize.NEWLINE too strictly #139783

Closed

Description

@BabakkGraphcore

Bug report

Bug description:

In python 3.13.8 calling inspect.getsourcelines on a decorated function with a comment between the decorator and the name only returns the function declaration, the body is skipped.

import inspect

def dummy(fn):
    return fn

@dummy
def test1(a, b):
    return a

@dummy
#comment
def test2(a, b):
    return a

print(inspect.getsourcelines(test1))
print("------------------")
print(inspect.getsourcelines(test2))

returns

(['@dummy\n', 'def test1(a, b):\n', '    return a\n'], 6)
------------------
(['@dummy\n', '#comment\n', 'def test2(a, b):\n'], 10)

the source of test2 is incomplete and missing the return statement.

CPython versions tested on:

3.13

Operating systems tested on:

Linux

Linked PRs

Activity

  1. added
    stdlibStandard Library Python modules in the Lib/ directory
    on Oct 8, 2025
  2. picnixz commented on Oct 8, 2025

    @picnixz
    Member

    I'll have a look at this.

  3. self-assigned this
    on Oct 8, 2025
  4. picnixz commented on Oct 8, 2025

    @picnixz
    Member

    The issue is with the BlockFinder which, because of the comment, considers that the body is not part of the function anymore.

  5. changed the title [-]`inspect.getsourcelines` incomplete when called on decorated function with a comment[/-] [+]`inspect.BlockFinder` handles `tokenize.NEWLINE` too strictly[/+] on Oct 8, 2025
  6. picnixz commented on Oct 8, 2025

    @picnixz
    Member

    Similar issues:

    @dummy
    
    @dummy
    def f():
        return 1
    
    print(inspect.getsourcelines(f))  # ['@dummy\n', '\n', '@dummy\n']

    So it's not only comments that are poorly handled, it's anything that "breaks" the "prelude" of the function (that is decorators). I'm not entirely sure we can do much thing here without adding a layer of complexity. It shouldn't be possible to say that the source lines of something only contains decorators or new lines/comments as this is not valid Python code. So, we should do something else.

    It would be quite easy to actually preprocess the source and eliminate "un-necessary" lines but then we'll need to handle the offset properly. In a single pass, we'll need to determine whether the block ended correctly or not.

    Similarly:

    @\
    dummy
    def f():
        return 1

    This is equivalent to use @dummy but again, the source lines will only consist of dummy and nothing else! But this is a separate issue actually, where findsource already struggles with that (it will not put @ and dummy together...)

  7. picnixz commented on Oct 8, 2025

    @picnixz
    Member

    I need to go now but I'll try to do something tomorrow or later this week. Thanks for reporting this!

  8. BabakkGraphcore commented on Oct 8, 2025

    @BabakkGraphcore
    Author

    I need to go now but I'll try to do something tomorrow or later this week. Thanks for reporting this!

    Great, thanks for picking it up so quickly1

  9. added a commit that references this issue on Oct 8, 2025
  10. serhiy-storchaka commented on Oct 9, 2025

    @serhiy-storchaka
    Member

    I worked with that code recently, so if you need help, I can help.

  11. picnixz commented on Oct 9, 2025

    @picnixz
    Member

    I am a bit time constrained so I would appreciate your help especially if it is something you recently worked on (I only skimmed through the implementation)

  12. albertvillanova commented on Oct 9, 2025

    @albertvillanova
    Contributor

    I confirm this issue and I give some information about severity and impact.

    Additional Impact: Breaking PyTorch JIT + HuggingFace Transformers

    This bug is affecting production code in the PyTorch and HuggingFace ecosystem.

    Real-world Example

    The HuggingFace transformers library contains multiple instances of this pattern. For example, in transformers/models/deberta_v2/modeling_deberta_v2.py (lines 105-108): https://github.com/huggingface/transformers/blob/be3fa93b298eec4182a0bb6c5e64270a5f1e8020/src/transformers/models/deberta_v2/modeling_deberta_v2.py#L105-L108

    @torch.jit.script
    # Copied from transformers.models.deberta.modeling_deberta.c2p_dynamic_expand
    def c2p_dynamic_expand(c2p_pos, query_layer, relative_pos):
        return c2p_pos.expand([query_layer.size(0), query_layer.size(1), query_layer.size(2), relative_pos.size(-1)])

    When this module is imported on Python 3.13.8, the @torch.jit.script decorator calls inspect.getsourcelines(), which returns only:

    @torch.jit.script
    # Copied from transformers.models.deberta.modeling_deberta.c2p_dynamic_expand
    def c2p_dynamic_expand(c2p_pos, query_layer, relative_pos):

    PyTorch then tries to parse this truncated source with ast.parse(), which fails with:

    File "<unknown>", line 3
        def c2p_dynamic_expand(c2p_pos, query_layer, relative_pos):
                                                                   ^
      IndentationError: expected an indented block after function definition on line 3

    Root Cause Confirmed

    I traced through the tokenization and can confirm the issue is in BlockFinder.tokeneater():

    1. After the decorator's NEWLINE token, self.indecorator is set to False
    2. The COMMENT token then enters the if not self.started and not self.indecorator: branch
    3. Since the token is not "def" or "class", it sets self.singleline = True
    4. This causes BlockFinder to treat the comment as a lambda/generator expression
    5. When the function signature's NEWLINE is encountered, it raises EndOfBlock prematurely

    Regression Confirmation

    ✅ Python 3.13.7: Works correctly
    ❌ Python 3.13.8: Broken

    This appears to be a side effect of the fix for gh-137477 (generator expressions):

  13. 24 remaining items

  14. picnixz commented on Oct 25, 2025

    @picnixz
    Member

    Could you ban the user above for spam @python/organization-owners? TiA.

  15. added a commit that references this issue on Dec 1, 2025
  16. added a commit that references this issue on Aug 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

3.13only security fixes3.14bugs and security fixes3.15bugs and security fixesstdlibStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or error

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions