Skip to content

atexit module breaks refleak check #139289

Open

Description

@gaogaotiantian

Bug report

Bug description:

If the test registers a callback with atexit module, refleak test will consider it a leak.

    def test_refleak(self):
        atexit.register(lambda: None)

This is the root cause of the buildbot failure of #139185. It's a couple of coincidences that caused the seemingly unrelated issue. Basically, clearing the module cache in test_zipimport made the module-level code in rlcompleter, which includes a register to atexit, run more than once.

There are a few possible approaches to fix this, but I did not find the solution that I'm immediately happy with.

I consider this a test framework bug as this should be a valid behavior. The ideal solution is to keep the atexit callbacks before running test in a loop and restore it after. However, atexit does not provide such an interface, public or private. You can either clear it or run it. The callbacks are stored in a state of the interpreter and we don't have any access to it.

Without that, we either need to somehow calculate the allocated memory by atexit, or hope that no one writes a test that writes to atexit. Of course there might be other ways that I did not think of.

CPython versions tested on:

CPython main branch

Operating systems tested on:

macOS

Linked PRs

Activity

  1. encukou commented on Sep 24, 2025

    @encukou
    Member

    This is intended behaviour: tests aren't supposed to “modify the environment” (affect other tests). IMO, the top-level code in rlcompleter is the anomaly. (It was written in 1997; who knew it would interfere with tests in 2025.)

    Maybe we could put Completer in another module, so you could use it without the side effects?

  2. gaogaotiantian commented on Sep 24, 2025

    @gaogaotiantian
    MemberAuthor

    I agree the top-level code in rlcompleter is not ideal. I was worried that changing it would break backward compatibility. Moving the Completer class to another module is a decent way to fix the issue, but that also requires some work - creating a new module in CPython is not the most trivial thing to do I think (docs, etc.).

    However, that seems like the most ideal solution we have for now and I'm happy if that can be done.

  3. ericsnowcurrently commented on Sep 24, 2025

    @ericsnowcurrently
    Member

    FWIW, we can put Completer in a private module, to avoid the extra work of a new public stdlib module.

  4. added 2 commits that reference this issue on Sep 26, 2025
  5. added 2 commits that reference this issue on Oct 9, 2025
  6. hugovk commented on Oct 10, 2025

    @hugovk
    Member

    Triage: ready to close this issue?

  7. encukou commented on Oct 10, 2025

    @encukou
    Member

    Unfortunately, the merged patch only fixed a symptom. Making Completer importable without side effects is still up for grabs.

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

    extension-modulesC modules in the Modules dirtestsTests in the Lib/test dirtype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions